diff options
author | unknown <cmiller@zippy.cornsilk.net> | 2006-10-17 11:23:07 -0400 |
---|---|---|
committer | unknown <cmiller@zippy.cornsilk.net> | 2006-10-17 11:23:07 -0400 |
commit | dd8a33c0bcbf092bca3aac03ae8f9414dc0ae9f8 (patch) | |
tree | beb33bece3b1deac1c65d795803da3b3d2e07f51 | |
parent | e1ff81bbce1bb71b447b754b47521db3e0cd92b0 (diff) | |
parent | 309962243d7ade38854c74d729d6dbb33c4a8ff4 (diff) | |
download | mariadb-git-dd8a33c0bcbf092bca3aac03ae8f9414dc0ae9f8.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into zippy.cornsilk.net:/home/cmiller/work/mysql/mysql-5.1-maint
BitKeeper/etc/collapsed:
auto-union
BitKeeper/etc/ignore:
auto-union
Makefile.am:
Auto merged
client/mysql.cc:
Auto merged
client/mysqldump.c:
Auto merged
client/mysqltest.c:
Auto merged
configure.in:
Auto merged
include/m_ctype.h:
Auto merged
include/my_global.h:
Auto merged
mysql-test/lib/mtr_process.pl:
Auto merged
mysql-test/mysql-test-run.pl:
Auto merged
mysql-test/r/binlog_row_mix_innodb_myisam.result:
Auto merged
mysql-test/r/csv.result:
Auto merged
mysql-test/r/ctype_utf8.result:
Auto merged
mysql-test/r/func_time.result:
Auto merged
mysql-test/r/mysql.result:
Auto merged
mysql-test/r/partition.result:
Auto merged
mysql-test/r/ps.result:
Auto merged
mysql-test/r/strict.result:
Auto merged
mysql-test/r/trigger.result:
Auto merged
mysql-test/r/warnings.result:
Auto merged
mysql-test/t/csv.test:
Auto merged
mysql-test/t/ctype_utf8.test:
Auto merged
mysql-test/t/func_time.test:
Auto merged
mysql-test/t/mysql.test:
Auto merged
mysql-test/t/partition.test:
Auto merged
mysql-test/t/ps.test:
Auto merged
mysql-test/t/trigger.test:
Auto merged
sql/field.cc:
Auto merged
sql/filesort.cc:
Auto merged
sql/item.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/item_timefunc.cc:
Auto merged
sql/item_timefunc.h:
Auto merged
sql/log.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/opt_range.cc:
Auto merged
sql/opt_range.h:
Auto merged
sql/set_var.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_update.cc:
Auto merged
sql/sql_view.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
vio/viosocket.c:
Auto merged
122 files changed, 6199 insertions, 4211 deletions
diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed index 79836bb030e..311c3813abf 100644 --- a/BitKeeper/etc/collapsed +++ b/BitKeeper/etc/collapsed @@ -5,5 +5,13 @@ 45001f7c3b2hhCXDKfUvzkX9TNe6VA 45002051rHJfMEXAIMiAZV0clxvKSA 4513d8e4Af4dQWuk13sArwofRgFDQw +45143312u0Tz4r0wPXCbUKwdHa2jWA +45143b90ewOQuTW8-jrB3ZSAQvMRJw +45184588w9U72A6KX1hUFeAC4shSHA +45185df8mZbxfp85FbA0VxUXkmDewA 4519a6c5BVUxEHTf5iJnjZkixMBs8g 451ab499rgdjXyOnUDqHu-wBDoS-OQ +451b110a3ZV6MITl93ehXk2wxrbW7g +45214442pBGT9KuZEGixBH71jTzbOA +45214a07hVsIGwvwa-WrO-jpeaSwVw +452a92d0-31-8wSzSfZi165fcGcXPA diff --git a/client/Makefile.am b/client/Makefile.am index d3e96dd126f..7d48e34b37b 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -46,7 +46,8 @@ mysqladmin_SOURCES = mysqladmin.cc mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c \ $(yassl_dummy_link_fix) -mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) +mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) \ + $(top_builddir)/mysys/libmysys.a mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c \ $(top_srcdir)/mysys/my_new.cc \ $(top_srcdir)/mysys/my_bit.c \ diff --git a/client/mysql.cc b/client/mysql.cc index 1dbdeb8be97..fc26a741632 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -386,6 +386,21 @@ int main(int argc,char *argv[]) else status.add_to_history=1; status.exit_status=1; + + { + /* + The file descriptor-layer may be out-of-sync with the file-number layer, + so we make sure that "stdout" is really open. If its file is closed then + explicitly close the FD layer. + */ + int stdout_fileno_copy; + stdout_fileno_copy= dup(fileno(stdout)); /* Okay if fileno fails. */ + if (stdout_fileno_copy == -1) + fclose(stdout); + else + close(stdout_fileno_copy); /* Clean up dup(). */ + } + load_defaults("my",load_default_groups,&argc,&argv); defaults_argv=argv; if (get_options(argc, (char **) argv)) diff --git a/client/mysqldump.c b/client/mysqldump.c index 2d2961e465c..8978239a5b0 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -3405,7 +3405,7 @@ static int do_reset_master(MYSQL *mysql_con) } -static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now) +static int start_transaction(MYSQL *mysql_con) { /* We use BEGIN for old servers. --single-transaction --master-data will fail @@ -3420,10 +3420,8 @@ static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now) "SET SESSION TRANSACTION ISOLATION " "LEVEL REPEATABLE READ") || mysql_query_with_error_report(mysql_con, 0, - consistent_read_now ? "START TRANSACTION " - "WITH CONSISTENT SNAPSHOT" : - "BEGIN")); + "/*!40100 WITH CONSISTENT SNAPSHOT */")); } @@ -3913,7 +3911,7 @@ int main(int argc, char **argv) if ((opt_lock_all_tables || opt_master_data) && do_flush_tables_read_lock(mysql)) goto err; - if (opt_single_transaction && start_transaction(mysql, test(opt_master_data))) + if (opt_single_transaction && start_transaction(mysql)) goto err; if (opt_delete_master_logs && do_reset_master(mysql)) goto err; diff --git a/client/mysqltest.c b/client/mysqltest.c index f9c4ae617fd..e2317560404 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -14,35 +14,24 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* mysqltest test tool - * See the manual for more information - * TODO: document better how mysqltest works - * - * Written by: - * Sasha Pachev <sasha@mysql.com> - * Matt Wagner <matt@mysql.com> - * Monty - * Jani - **/ - -/********************************************************************** - TODO: +/* + mysqltest -- Do comparison line by line, instead of doing a full comparison of - the text file. This will save space as we don't need to keep many - results in memory. It will also make it possible to do simple - 'comparison' fixes like accepting the result even if a float differed - in the last decimals. + Tool used for executing a .test file -- Don't buffer lines from the test that you don't expect to need - again. + See the "MySQL Test framework manual" for more information + http://dev.mysql.com/doc/mysqltest/en/index.html -- Change 'read_line' to be faster by using the readline.cc code; - We can do better than calling feof() for each character! + Please keep the test framework tools identical in all versions! -**********************************************************************/ + Written by: + Sasha Pachev <sasha@mysql.com> + Matt Wagner <matt@mysql.com> + Monty + Jani +*/ -#define MTEST_VERSION "2.6" +#define MTEST_VERSION "3.0" #include <my_global.h> #include <mysql_embed.h> @@ -51,18 +40,18 @@ #include <mysql.h> #include <mysql_version.h> #include <mysqld_error.h> +#include <errmsg.h> #include <m_ctype.h> #include <my_dir.h> -#include <errmsg.h> /* Error codes */ #include <hash.h> #include <my_getopt.h> #include <stdarg.h> -#include <sys/stat.h> #include <violite.h> -#include "my_regex.h" /* Our own version of lib */ +#include "my_regex.h" /* Our own version of regex */ #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif + #ifndef WEXITSTATUS # ifdef __WIN__ # define WEXITSTATUS(stat_val) (stat_val) @@ -70,169 +59,116 @@ # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) # endif #endif -/* MAX_QUERY is 256K -- there is a test in sp-big that is >128K */ -#define MAX_QUERY (256*1024) -#define MAX_VAR_NAME 256 -#define MAX_COLUMNS 256 -#define MAX_CONS 128 -#define MAX_INCLUDE_DEPTH 16 -#define INIT_Q_LINES 1024 -#define MIN_VAR_ALLOC 32 -#define BLOCK_STACK_DEPTH 32 -#define MAX_EXPECTED_ERRORS 10 -#define QUERY_SEND 1 -#define QUERY_REAP 2 -#define MAX_SERVER_ARGS 64 - - -#define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */ -#define DEFAULT_DELIMITER ";" -#define MAX_DELIMITER 16 - -#define RESULT_OK 0 -#define RESULT_CONTENT_MISMATCH 1 -#define RESULT_LENGTH_MISMATCH 2 - -enum {OPT_SKIP_SAFEMALLOC=256, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, - OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL, - OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, - OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES, - OPT_MARK_PROGRESS}; - -/* ************************************************************************ */ -/* - The list of error codes to --error are stored in an internal array of - structs. This struct can hold numeric SQL error codes or SQLSTATE codes - as strings. The element next to the last active element in the list is - set to type ERR_EMPTY. When an SQL statement returns an error, we use - this list to check if this is an expected error. -*/ - -enum match_err_type -{ - ERR_EMPTY= 0, - ERR_ERRNO, - ERR_SQLSTATE -}; - -typedef struct -{ - enum match_err_type type; - union - { - uint errnum; - char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */ - } code; -} match_err; - -typedef struct -{ - const char *name; - long code; -} st_error; -static st_error global_error[] = -{ -#include <mysqld_ername.h> - { 0, 0 } +#define MAX_VAR_NAME_LENGTH 256 +#define MAX_COLUMNS 256 +#define MAX_EMBEDDED_SERVER_ARGS 64 +#define MAX_DELIMITER_LENGTH 16 + +/* Flags controlling send and reap */ +#define QUERY_SEND_FLAG 1 +#define QUERY_REAP_FLAG 2 + + enum { + RESULT_OK= 0, + RESULT_CONTENT_MISMATCH= 1, + RESULT_LENGTH_MISMATCH= 2 + }; + +enum { + OPT_SKIP_SAFEMALLOC=256, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, + OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL, + OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, + OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES, + OPT_MARK_PROGRESS }; -static match_err global_expected_errno[MAX_EXPECTED_ERRORS]; -static uint global_expected_errors; - -/* ************************************************************************ */ - static int record= 0, opt_sleep= -1; -static char *db = 0, *pass=0; -const char *user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; +static char *db= 0, *pass= 0; +const char *user= 0, *host= 0, *unix_sock= 0, *opt_basedir= "./"; const char *opt_include= 0; -static int port = 0; +static int port= 0; static int opt_max_connect_retries; -static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0; +static my_bool opt_compress= 0, silent= 0, verbose= 0; static my_bool tty_password= 0; static my_bool opt_mark_progress= 0; static my_bool ps_protocol= 0, ps_protocol_enabled= 0; static my_bool sp_protocol= 0, sp_protocol_enabled= 0; static my_bool view_protocol= 0, view_protocol_enabled= 0; static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0; -static my_bool opt_valgrind_test= 0; -static int parsing_disabled= 0; +static my_bool parsing_disabled= 0; +static my_bool display_result_vertically= FALSE, display_metadata= FALSE; +static my_bool disable_query_log= 0, disable_result_log= 0; +static my_bool disable_warnings= 0, disable_ps_warnings= 0; +static my_bool disable_info= 1; +static my_bool abort_on_error= 1; static char **default_argv; -static const char *load_default_groups[]= { "mysqltest","client",0 }; -static char line_buffer[MAX_DELIMITER], *line_buffer_pos= line_buffer; +static const char *load_default_groups[]= { "mysqltest", "client", 0 }; +static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; -typedef struct -{ - FILE* file; - const char *file_name; - uint lineno; /* Current line in file */ -} test_file; +static uint start_lineno= 0; /* Start line of current command */ + +static char delimiter[MAX_DELIMITER_LENGTH]= ";"; +static uint delimiter_length= 1; -static test_file file_stack[MAX_INCLUDE_DEPTH]; -static test_file* cur_file; -static test_file* file_stack_end; -uint start_lineno= 0; /* Start line of query */ +static char TMPDIR[FN_REFLEN]; -/* Stores regex substitutions */ +/* Block stack */ +enum block_cmd { + cmd_none, + cmd_if, + cmd_while +}; -struct st_regex +struct st_block { - char* pattern; /* Pattern to be replaced */ - char* replace; /* String or expression to replace the pattern with */ - int icase; /* true if the match is case insensitive */ + int line; /* Start line of block */ + my_bool ok; /* Should block be executed */ + enum block_cmd cmd; /* Command owning the block */ }; -struct st_replace_regex +static struct st_block block_stack[32]; +static struct st_block *cur_block, *block_stack_end; + +/* Open file stack */ +struct st_test_file { - 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; + FILE* file; + const char *file_name; + uint lineno; /* Current line in file */ }; -struct st_replace_regex *glob_replace_regex= 0; - -static char TMPDIR[FN_REFLEN]; -static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; -static uint delimiter_length= 1; +static struct st_test_file file_stack[16]; +static struct st_test_file* cur_file; +static struct st_test_file* file_stack_end; -/* Block stack */ -enum block_cmd { cmd_none, cmd_if, cmd_while }; -typedef struct -{ - int line; /* Start line of block */ - my_bool ok; /* Should block be executed */ - enum block_cmd cmd; /* Command owning the block */ -} BLOCK; -static BLOCK block_stack[BLOCK_STACK_DEPTH]; -static BLOCK *cur_block, *block_stack_end; static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ static const char *charset_name= "latin1"; /* Default character set name */ -static int embedded_server_arg_count=0; -static char *embedded_server_args[MAX_SERVER_ARGS]; +static const char *embedded_server_groups[]= +{ + "server", + "embedded", + "mysqltest_SERVER", + NullS +}; -static my_bool display_result_vertically= FALSE, display_metadata= FALSE; +static int embedded_server_arg_count=0; +static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS]; -/* See the timer_output() definition for details */ +/* + Timer related variables + See the timer_output() definition for details +*/ static char *timer_file = NULL; -static ulonglong timer_start, progress_start= 0; -static int got_end_timer= FALSE; +static ulonglong timer_start; static void timer_output(void); static ulonglong timer_now(void); +static ulonglong progress_start= 0; + /* 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 */ @@ -242,47 +178,25 @@ static void init_re(void); static int match_re(my_regex_t *, char *); static void free_re(void); -static int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, - char *string, int icase); - -static const char *embedded_server_groups[]= -{ - "server", - "embedded", - "mysqltest_SERVER", - NullS -}; - DYNAMIC_ARRAY q_lines; #include "sslopt-vars.h" -typedef struct -{ - char file[FN_REFLEN]; - ulong pos; -} MASTER_POS ; - -struct connection +struct { - MYSQL mysql; - /* Used when creating views and sp, to avoid implicit commit */ - MYSQL* util_mysql; - char *name; - MYSQL_STMT* stmt; -}; + int read_lines,current_line; +} parser; -typedef struct +struct { - int read_lines,current_line; -} PARSER; + char file[FN_REFLEN]; + ulong pos; +} master_pos; -PARSER parser; -MASTER_POS master_pos; /* if set, all results are concated and compared against this file */ -const char *result_file = 0; +const char *result_file_name= 0; -typedef struct +typedef struct st_var { char *name; int name_len; @@ -295,70 +209,68 @@ typedef struct char *env_s; } VAR; -VAR var_reg[10]; /*Perl/shell-like variable registers */ -HASH var_hash; -my_bool disable_query_log=0, disable_result_log=0, disable_warnings=0; -my_bool disable_ps_warnings= 0; -my_bool disable_info= 1; /* By default off */ -my_bool abort_on_error= 1; +VAR var_reg[10]; -struct connection cons[MAX_CONS]; -struct connection* cur_con, *next_con, *cons_end; +HASH var_hash; - /* Add new commands before Q_UNKNOWN !*/ +struct st_connection +{ + MYSQL mysql; + /* Used when creating views and sp, to avoid implicit commit */ + MYSQL* util_mysql; + char *name; + MYSQL_STMT* stmt; +}; +struct st_connection connections[128]; +struct st_connection* cur_con, *next_con, *connections_end; +/* + List of commands in mysqltest + Must match the "command_names" array + Add new commands before Q_UNKNOWN! +*/ enum enum_commands { -Q_CONNECTION=1, Q_QUERY, -Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP, -Q_INC, Q_DEC, -Q_SOURCE, Q_DISCONNECT, -Q_LET, Q_ECHO, -Q_WHILE, Q_END_BLOCK, -Q_SYSTEM, Q_RESULT, -Q_REQUIRE, Q_SAVE_MASTER_POS, -Q_SYNC_WITH_MASTER, -Q_SYNC_SLAVE_WITH_MASTER, -Q_ERROR, -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_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, -Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, -Q_WAIT_FOR_SLAVE_TO_STOP, -Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, -Q_ENABLE_PS_WARNINGS, Q_DISABLE_PS_WARNINGS, -Q_ENABLE_INFO, Q_DISABLE_INFO, -Q_ENABLE_METADATA, Q_DISABLE_METADATA, -Q_EXEC, Q_DELIMITER, -Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR, -Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, -Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, -Q_START_TIMER, Q_END_TIMER, -Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, -Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, -Q_IF, -Q_DISABLE_PARSING, Q_ENABLE_PARSING, -Q_REPLACE_REGEX, Q_DIE, - -Q_UNKNOWN, /* Unknown command. */ -Q_COMMENT, /* Comments, ignored. */ -Q_COMMENT_WITH_COMMAND + Q_CONNECTION=1, Q_QUERY, + Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP, + Q_INC, Q_DEC, + Q_SOURCE, Q_DISCONNECT, + Q_LET, Q_ECHO, + Q_WHILE, Q_END_BLOCK, + Q_SYSTEM, Q_RESULT, + Q_REQUIRE, Q_SAVE_MASTER_POS, + Q_SYNC_WITH_MASTER, + Q_SYNC_SLAVE_WITH_MASTER, + Q_ERROR, + 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_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, + Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, + Q_WAIT_FOR_SLAVE_TO_STOP, + Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, + Q_ENABLE_PS_WARNINGS, Q_DISABLE_PS_WARNINGS, + Q_ENABLE_INFO, Q_DISABLE_INFO, + Q_ENABLE_METADATA, Q_DISABLE_METADATA, + Q_EXEC, Q_DELIMITER, + Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR, + Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, + Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, + Q_START_TIMER, Q_END_TIMER, + Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, + Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, + Q_IF, + Q_DISABLE_PARSING, Q_ENABLE_PARSING, + Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST, + Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, + + Q_UNKNOWN, /* Unknown command. */ + Q_COMMENT, /* Comments, ignored. */ + Q_COMMENT_WITH_COMMAND }; -/* this should really be called command */ -struct st_query -{ - char *query, *query_buf,*first_argument,*last_argument,*end; - int first_word_len; - my_bool abort_on_error, require_file; - match_err expected_errno[MAX_EXPECTED_ERRORS]; - uint expected_errors; - char record_file[FN_REFLEN]; - enum enum_commands type; -}; const char *command_names[]= { @@ -427,69 +339,116 @@ const char *command_names[]= "disable_parsing", "enable_parsing", "replace_regex", + "remove_file", + "file_exists", + "write_file", + "copy_file", + "perl", "die", 0 }; -TYPELIB command_typelib= {array_elements(command_names),"", - command_names, 0}; - -DYNAMIC_STRING ds_res, ds_progress; -static void die(const char *fmt, ...); -static void init_var_hash(); -static VAR* var_from_env(const char *, const char *); -static byte* get_var_key(const byte* rec, uint* len, my_bool t); -static VAR* var_init(VAR* v, const char *name, int name_len, const char *val, - int val_len); -static void var_free(void* v); +/* + The list of error codes to --error are stored in an internal array of + structs. This struct can hold numeric SQL error codes, error names or + SQLSTATE codes as strings. The element next to the last active element + in the list is set to type ERR_EMPTY. When an SQL statement returns an + error, we use this list to check if this is an expected error. +*/ +enum match_err_type +{ + ERR_EMPTY= 0, + ERR_ERRNO, + ERR_SQLSTATE +}; -void dump_result_to_reject_file(const char *record_file, char *buf, int size); -void dump_result_to_log_file(const char *record_file, char *buf, int size); +struct st_match_err +{ + enum match_err_type type; + union + { + uint errnum; + char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */ + } code; +}; -int close_connection(struct st_query*); -static void set_charset(struct st_query*); -VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, - my_bool ignore_not_existing); -int eval_expr(VAR* v, const char *p, const char** p_end); -static int read_server_arguments(const char *name); +struct st_expected_errors +{ + struct st_match_err err[10]; + uint count; +}; +static struct st_expected_errors saved_expected_errors; -/* Definitions for replace result */ +struct st_command +{ + char *query, *query_buf,*first_argument,*last_argument,*end; + int first_word_len, query_len; + my_bool abort_on_error; + struct st_expected_errors expected_errors; + char require_file[FN_REFLEN]; + enum enum_commands type; +}; -typedef struct st_pointer_array { /* when using array-strings */ - TYPELIB typelib; /* Pointer to strings */ - byte *str; /* Strings is here */ - int7 *flag; /* Flag about each var. */ - uint array_allocs,max_count,length,max_length; -} POINTER_ARRAY; +TYPELIB command_typelib= {array_elements(command_names),"", + command_names, 0}; -struct st_replace; -struct st_replace *init_replace(my_string *from, my_string *to, uint count, - my_string word_end_chars); -void free_replace(); -static void free_replace_regex(); -static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); -static void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, - const char *from, int len); -void free_pointer_array(POINTER_ARRAY *pa); -static void do_eval(DYNAMIC_STRING *query_eval, const char *query, - my_bool pass_through_escape_chars); -static void str_to_file(const char *fname, char *str, int size); +DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages; + +void die(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; +void abort_not_supported_test(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; +void verbose_msg(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; +void warning_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); +my_bool match_delimiter(int c, const char *delim, uint length); +void dump_result_to_reject_file(char *buf, int size); +void dump_result_to_log_file(char *buf, int size); +void dump_warning_messages(); +void dump_progress(); + +void do_eval(DYNAMIC_STRING *query_eval, const char *query, + const char *query_end, my_bool pass_through_escape_chars); +void str_to_file(const char *fname, char *str, int size); #ifdef __WIN__ -static void free_tmp_sh_file(); -static void free_win_path_patterns(); +void free_tmp_sh_file(); +void free_win_path_patterns(); #endif -struct st_replace *glob_replace; static int eval_result = 0; -/* For column replace */ -char *replace_column[MAX_COLUMNS]; -uint max_replace_column= 0; +/* For replace_column */ +static char *replace_column[MAX_COLUMNS]; +static uint max_replace_column= 0; +void do_get_replace_column(struct st_command*); +void free_replace_column(); + +/* For replace */ +void do_get_replace(struct st_command *command); +void free_replace(); + +/* For replace_regex */ +void do_get_replace_regex(struct st_command *command); +void free_replace_regex(); + + +void free_all_replace(){ + free_replace(); + free_replace_regex(); + free_replace_column(); +} -static void get_replace_column(struct st_query *q); -static void free_replace_column(); /* Disable functions that only exist in MySQL 4.0 */ #if MYSQL_VERSION_ID < 40000 @@ -498,35 +457,40 @@ 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 -static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, - int len); -static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); -static void handle_error(const char *query, struct st_query *q, - unsigned int err_errno, const char *err_error, - const char *err_sqlstate, DYNAMIC_STRING *ds); -static void handle_no_error(struct st_query *q); -static void do_eval(DYNAMIC_STRING* query_eval, const char *query, - my_bool pass_through_escape_chars) +void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, + int len); +void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); +void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val); + +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 do_eval(DYNAMIC_STRING *query_eval, const char *query, + const char *query_end, my_bool pass_through_escape_chars) { const char *p; register char c, next_c; register int escaped = 0; - VAR* v; + VAR *v; DBUG_ENTER("do_eval"); - for (p= query; (c = *p); ++p) + for (p= query; (c= *p) && p < query_end; ++p) { switch(c) { case '$': if (escaped) { - escaped = 0; + escaped= 0; dynstr_append_mem(query_eval, p, 1); } else { - if (!(v = var_get(p, &p, 0, 0))) + if (!(v= var_get(p, &p, 0, 0))) die("Bad variable in eval"); dynstr_append_mem(query_eval, v->str_val, v->str_val_len); } @@ -535,13 +499,13 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char *query, next_c= *(p+1); if (escaped) { - escaped = 0; + escaped= 0; dynstr_append_mem(query_eval, p, 1); } - else if (next_c == '\\' || next_c == '$') + else if (next_c == '\\' || next_c == '$' || next_c == '"') { - /* Set escaped only if next char is \ or $ */ - escaped = 1; + /* Set escaped only if next char is \, " or $ */ + escaped= 1; if (pass_through_escape_chars) { @@ -561,10 +525,131 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char *query, } -static void close_cons() +enum arg_type +{ + ARG_STRING, + ARG_REST +}; + +struct command_arg { + const char *argname; /* Name of argument */ + enum arg_type type; /* Type of argument */ + my_bool required; /* Argument required */ + DYNAMIC_STRING *ds; /* Storage for argument */ + const char *description; /* Description of the argument */ +}; + + +void check_command_args(struct st_command *command, + const char *arguments, + const struct command_arg *args, + int num_args, const char delimiter_arg) +{ + int i; + const char *ptr= arguments; + const char *start; + + DBUG_ENTER("check_command_args"); + DBUG_PRINT("enter", ("num_args: %d", num_args)); + for (i= 0; i < num_args; i++) + { + const struct command_arg *arg= &args[i]; + + switch (arg->type) + { + /* A string */ + case ARG_STRING: + /* Skip leading spaces */ + while (*ptr && *ptr == ' ') + ptr++; + start= ptr; + /* Find end of arg, terminated by "delimiter_arg" */ + while (*ptr && *ptr != delimiter_arg) + ptr++; + if (ptr > start) + { + init_dynamic_string(arg->ds, 0, ptr-start, 32); + do_eval(arg->ds, start, ptr, FALSE); + } + else + { + /* Empty string */ + init_dynamic_string(arg->ds, "", 0, 0); + } + command->last_argument= (char*)ptr; + + /* Step past the delimiter */ + if (*ptr && *ptr == delimiter_arg) + ptr++; + DBUG_PRINT("info", ("val: %s", arg->ds->str)); + break; + + /* Rest of line */ + case ARG_REST: + start= ptr; + init_dynamic_string(arg->ds, 0, command->query_len, 256); + do_eval(arg->ds, start, command->end, FALSE); + command->last_argument= command->end; + DBUG_PRINT("info", ("val: %s", arg->ds->str)); + break; + + default: + DBUG_ASSERT("Unknown argument type"); + break; + } + + /* Check required arg */ + if (arg->ds->length == 0 && arg->required) + die("Missing required argument '%s' to command '%.*s'", arg->argname, + command->first_word_len, command->query); + + } + DBUG_VOID_RETURN; +} + + +void handle_command_error(struct st_command *command, uint error) +{ + DBUG_ENTER("handle_command_error"); + DBUG_PRINT("enter", ("error: %d", error)); + if (error != 0) + { + uint i; + + if (command->abort_on_error) + die("command \"%.*s\" failed with error %d", + command->first_word_len, command->query, error); + for (i= 0; i < command->expected_errors.count; i++) + { + DBUG_PRINT("info", ("expected error: %d", + command->expected_errors.err[i].code.errnum)); + if ((command->expected_errors.err[i].type == ERR_ERRNO) && + (command->expected_errors.err[i].code.errnum == error)) + { + DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d", + command->first_word_len, command->query, error)); + DBUG_VOID_RETURN; + } + } + die("command \"%.*s\" failed with wrong error: %d", + command->first_word_len, command->query, error); + } + 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...", + command->first_word_len, command->query, + command->expected_errors.err[0].code.errnum); + } + DBUG_VOID_RETURN; +} + + +void close_connections() { - DBUG_ENTER("close_cons"); - for (--next_con; next_con >= cons; --next_con) + DBUG_ENTER("close_connections"); + for (--next_con; next_con >= connections; --next_con) { if (next_con->stmt) mysql_stmt_close(next_con->stmt); @@ -578,14 +663,16 @@ static void close_cons() } -static void close_files() +void close_files() { DBUG_ENTER("close_files"); for (; cur_file >= file_stack; cur_file--) { - DBUG_PRINT("info", ("file_name: %s", cur_file->file_name)); if (cur_file->file && cur_file->file != stdin) + { + DBUG_PRINT("info", ("closing file: %s", cur_file->file_name)); my_fclose(cur_file->file, MYF(0)); + } my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; } @@ -593,22 +680,22 @@ static void close_files() } -static void free_used_memory() +void free_used_memory() { uint i; DBUG_ENTER("free_used_memory"); - close_cons(); + close_connections(); close_files(); hash_free(&var_hash); - for (i=0 ; i < q_lines.elements ; i++) + for (i= 0 ; i < q_lines.elements ; i++) { - struct st_query **q= dynamic_element(&q_lines, i, struct st_query**); + struct st_command **q= dynamic_element(&q_lines, i, struct st_command**); my_free((gptr) (*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) (*q),MYF(0)); } - for (i=0; i < 10; i++) + for (i= 0; i < 10; i++) { if (var_reg[i].alloced_len) my_free(var_reg[i].str_val, MYF(MY_WME)); @@ -618,8 +705,8 @@ static void free_used_memory() delete_dynamic(&q_lines); dynstr_free(&ds_res); dynstr_free(&ds_progress); - free_replace(); - free_replace_column(); + dynstr_free(&ds_warning_messages); + free_all_replace(); my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); free_defaults(default_argv); mysql_server_end(); @@ -631,10 +718,12 @@ static void free_used_memory() DBUG_VOID_RETURN; } -static void die(const char *fmt, ...) + +void die(const char *fmt, ...) { va_list args; DBUG_ENTER("die"); + DBUG_PRINT("enter", ("start_lineno: %d", start_lineno)); /* Print the error message */ va_start(args, fmt); @@ -653,8 +742,12 @@ static void die(const char *fmt, ...) va_end(args); /* Dump the result that has been accumulated so far to .log file */ - if (result_file && ds_res.length) - dump_result_to_log_file(result_file, ds_res.str, ds_res.length); + if (result_file_name && ds_res.length) + dump_result_to_log_file(ds_res.str, ds_res.length); + + /* Dump warning messages */ + if (result_file_name && ds_warning_messages.length) + dump_warning_messages(); /* Clean up and exit */ free_used_memory(); @@ -667,10 +760,10 @@ static void die(const char *fmt, ...) } -static void abort_not_supported_test(const char *fmt, ...) +void abort_not_supported_test(const char *fmt, ...) { va_list args; - test_file* err_file= cur_file; + struct st_test_file* err_file= cur_file; DBUG_ENTER("abort_not_supported_test"); /* Print include filestack */ @@ -706,7 +799,14 @@ static void abort_not_supported_test(const char *fmt, ...) exit(62); } -static void verbose_msg(const char *fmt, ...) + +void abort_not_in_this_version() +{ + die("Not available in this version of mysqltest"); +} + + +void verbose_msg(const char *fmt, ...) { va_list args; DBUG_ENTER("verbose_msg"); @@ -715,6 +815,9 @@ static void verbose_msg(const char *fmt, ...) va_start(args, fmt); fprintf(stderr, "mysqltest: "); + if (cur_file && cur_file != file_stack) + fprintf(stderr, "In included file \"%s\": ", + cur_file->file_name); if (start_lineno != 0) fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); @@ -725,14 +828,46 @@ static void verbose_msg(const char *fmt, ...) } -void init_parser() +void warning_msg(const char *fmt, ...) { - parser.current_line= parser.read_lines= 0; - memset(&var_reg, 0, sizeof(var_reg)); + va_list args; + char buff[512]; + size_t len; + DBUG_ENTER("warning_msg"); + + va_start(args, fmt); + dynstr_append(&ds_warning_messages, "mysqltest: "); + if (start_lineno != 0) + { + dynstr_append(&ds_warning_messages, "Warning detected "); + if (cur_file && cur_file != file_stack) + { + len= my_snprintf(buff, sizeof(buff), "in included file %s ", + cur_file->file_name); + dynstr_append_mem(&ds_warning_messages, + buff, len); + } + len= my_snprintf(buff, sizeof(buff), "at line %d: ", + start_lineno); + dynstr_append_mem(&ds_warning_messages, + buff, len); + } +#ifndef __WIN__ + len= vsnprintf(buff, sizeof(buff), fmt, args); + dynstr_append_mem(&ds_warning_messages, buff, len); +#endif + dynstr_append(&ds_warning_messages, "\n"); + va_end(args); + + DBUG_VOID_RETURN; } -static int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) +/* + Compare content of the string ds to content of file fname +*/ + +int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { MY_STAT stat_info; char *tmp, *res_ptr; @@ -761,19 +896,20 @@ static int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) DBUG_RETURN(RESULT_LENGTH_MISMATCH); } if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) - die(NullS); + die("Out of memory"); if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0) - die(NullS); + die("Failed to open file %s", eval_file); if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP))) - die(NullS); + die("Failed to read from file %s, errno: %d", eval_file, errno); tmp[stat_info.st_size] = 0; - init_dynamic_string(&res_ds, "", 0, 65536); + init_dynamic_string(&res_ds, "", stat_info.st_size+256, 256); if (eval_result) { - do_eval(&res_ds, tmp, FALSE); - res_ptr = res_ds.str; - if ((res_len = res_ds.length) != ds->length) + do_eval(&res_ds, tmp, tmp + stat_info.st_size, FALSE); + res_ptr= res_ds.str; + res_len= res_ds.length; + if (res_len != ds->length) { res= RESULT_LENGTH_MISMATCH; goto err; @@ -794,48 +930,41 @@ err: MY_REPLACE_EXT), res_ptr, res_len); + dynstr_free(&res_ds); my_free((gptr) tmp, MYF(0)); my_close(fd, MYF(MY_WME)); - dynstr_free(&res_ds); DBUG_RETURN(res); } + /* - Check the content of ds against content of file fname + Check the content of ds against result file SYNOPSIS check_result ds - content to be checked - fname - name of file to check against - require_option - if set and check fails, the test will be aborted - with the special exit code "not supported test" RETURN VALUES - error - the function will not return + error - the function will not return */ -static void check_result(DYNAMIC_STRING* ds, const char *fname, - my_bool require_option) + +void check_result(DYNAMIC_STRING* ds) { - int res= dyn_string_cmp(ds, fname); DBUG_ENTER("check_result"); + DBUG_ASSERT(result_file_name); - if (res && require_option) + switch (dyn_string_cmp(ds, result_file_name)) { - char reason[FN_REFLEN]; - fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR); - abort_not_supported_test("Test requires: '%s'", reason); - } - switch (res) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: - dump_result_to_reject_file(fname, ds->str, ds->length); + dump_result_to_reject_file(ds->str, ds->length); die("Result length mismatch"); break; case RESULT_CONTENT_MISMATCH: - dump_result_to_reject_file(fname, ds->str, ds->length); + dump_result_to_reject_file(ds->str, ds->length); die("Result content mismatch"); break; default: /* impossible */ @@ -846,13 +975,109 @@ static void check_result(DYNAMIC_STRING* ds, const char *fname, } -VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, +/* + Check the content of ds against a require file + If match fails, abort the test with special error code + indicating that test is not supported + + SYNOPSIS + check_result + ds - content to be checked + fname - name of file to check against + + RETURN VALUES + error - the function will not return + +*/ + +void check_require(DYNAMIC_STRING* ds, const char *fname) +{ + DBUG_ENTER("check_require"); + + if (dyn_string_cmp(ds, fname)) + { + char reason[FN_REFLEN]; + fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR); + abort_not_supported_test("Test requires: '%s'", reason); + } + DBUG_VOID_RETURN; +} + + +static byte *get_var_key(const byte* var, uint* len, + my_bool __attribute__((unused)) t) +{ + register char* key; + key = ((VAR*)var)->name; + *len = ((VAR*)var)->name_len; + return (byte*)key; +} + + +VAR *var_init(VAR *v, const char *name, int name_len, const char *val, + int val_len) +{ + int val_alloc_len; + VAR *tmp_var; + if (!name_len && name) + name_len = strlen(name); + if (!val_len && val) + val_len = strlen(val) ; + val_alloc_len = val_len + 16; /* room to grow */ + if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var) + + name_len+1, MYF(MY_WME)))) + die("Out of memory"); + + tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0; + tmp_var->alloced = (v == 0); + + if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME)))) + die("Out of memory"); + + memcpy(tmp_var->name, name, name_len); + if (val) + { + memcpy(tmp_var->str_val, val, val_len); + tmp_var->str_val[val_len]= 0; + } + 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; + tmp_var->env_s = 0; + return tmp_var; +} + + +void var_free(void *v) +{ + my_free(((VAR*) v)->str_val, MYF(MY_WME)); + if (((VAR*)v)->alloced) + my_free((char*) v, MYF(MY_WME)); +} + + +VAR* var_from_env(const char *name, const char *def_val) +{ + const char *tmp; + VAR *v; + if (!(tmp = getenv(name))) + tmp = def_val; + + v = var_init(0, name, strlen(name), tmp, strlen(tmp)); + my_hash_insert(&var_hash, (byte*)v); + return v; +} + + +VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw, my_bool ignore_not_existing) { int digit; - VAR* v; + VAR *v; DBUG_ENTER("var_get"); - DBUG_PRINT("enter",("var_name: %s",var_name)); + DBUG_PRINT("enter", ("var_name: %s",var_name)); if (*var_name != '$') goto err; @@ -871,16 +1096,16 @@ VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, die("Empty variable"); } length= (uint) (var_name - save_var_name); - if (length >= MAX_VAR_NAME) + if (length >= MAX_VAR_NAME_LENGTH) die("Too long variable name: %s", save_var_name); if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length))) { - char buff[MAX_VAR_NAME+1]; + char buff[MAX_VAR_NAME_LENGTH+1]; strmake(buff, save_var_name, length); v= var_from_env(buff, ""); } - var_name--; /* Point at last character */ + var_name--; /* Point at last character */ } else v = var_reg + digit; @@ -901,7 +1126,8 @@ err: DBUG_RETURN(0); } -static VAR *var_obtain(const char *name, int len) + +VAR *var_obtain(const char *name, int len) { VAR* v; if ((v = (VAR*)hash_search(&var_hash, name, len))) @@ -911,16 +1137,18 @@ static VAR *var_obtain(const char *name, int len) return v; } + /* - if variable starts with a $ it is regarded as a local test varable - if not it is treated as a environment variable, and the corresponding environment variable will be updated */ -int var_set(const char *var_name, const char *var_name_end, - const char *var_val, const char *var_val_end) + +void var_set(const char *var_name, const char *var_name_end, + const char *var_val, const char *var_val_end) { - int digit, result, env_var= 0; - VAR* v; + int digit, env_var= 0; + VAR *v; DBUG_ENTER("var_set"); DBUG_PRINT("enter", ("var_name: '%.*s' = '%.*s' (length: %d)", (int) (var_name_end - var_name), var_name, @@ -932,15 +1160,15 @@ int var_set(const char *var_name, const char *var_name_end, else var_name++; - digit = *var_name - '0'; + digit= *var_name - '0'; if (!(digit < 10 && digit >= 0)) { - v = var_obtain(var_name, (uint) (var_name_end - var_name)); + v= var_obtain(var_name, (uint) (var_name_end - var_name)); } else - v = var_reg + digit; + v= var_reg + digit; - result= eval_expr(v, var_val, (const char**) &var_val_end); + eval_expr(v, var_val, (const char**) &var_val_end); if (env_var) { @@ -957,7 +1185,183 @@ int var_set(const char *var_name, const char *var_name_end, putenv(v->env_s); my_free((gptr)old_env_s, MYF(MY_ALLOW_ZERO_PTR)); } - DBUG_RETURN(result); + DBUG_VOID_RETURN; +} + +/* + Store an integer (typically the returncode of the last SQL) + statement in the mysqltest builtin variable $mysql_errno, by + simulating of a user statement "let $mysql_errno= <integer>" +*/ + +void var_set_errno(int sql_errno) +{ + /* TODO MASV make easier */ + const char *var_name= "$mysql_errno"; + char var_val[21]; + uint length= my_sprintf(var_val, (var_val, "%d", sql_errno)); + var_set(var_name, var_name + 12, var_val, var_val + length); + return; +} + + +/* + Set variable from the result of a query + + SYNOPSIS + var_query_set() + var variable to set from query + query start of query string to execute + query_end end of the query string to execute + + + DESCRIPTION + let @<var_name> = `<query>` + + Execute the query and assign the first row of result to var as + a tab separated strings + + Also assign each column of the result set to + variable "$<var_name>_<column_name>" + Thus the tab separated output can be read from $<var_name> and + and each individual column can be read as $<var_name>_<col_name> + +*/ + +void var_query_set(VAR *var, const char *query, const char** query_end) +{ + char* end = (char*)((query_end && *query_end) ? + *query_end : query + strlen(query)); + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL* mysql = &cur_con->mysql; + DBUG_ENTER("var_query_set"); + LINT_INIT(res); + + while (end > query && *end != '`') + --end; + if (query == end) + die("Syntax error in query, missing '`'"); + ++query; + + if (mysql_real_query(mysql, query, (int)(end - query)) || + !(res = mysql_store_result(mysql))) + { + *end = 0; + die("Error running query '%s': %d %s", query, + mysql_errno(mysql), mysql_error(mysql)); + } + + if ((row = mysql_fetch_row(res)) && row[0]) + { + /* + Concatenate all row results with tab in between to allow us to work + with results from many columns (for example from SHOW VARIABLES) + */ + DYNAMIC_STRING result; + uint i; + ulong *lengths; + char *end; +#ifdef NOT_YET + MYSQL_FIELD *fields= mysql_fetch_fields(res); +#endif + + init_dynamic_string(&result, "", 2048, 2048); + lengths= mysql_fetch_lengths(res); + for (i=0; i < mysql_num_fields(res); i++) + { + if (row[0]) + { +#ifdef NOT_YET + /* Add to <var_name>_<col_name> */ + uint j; + char var_col_name[MAX_VAR_NAME_LENGTH]; + uint length= snprintf(var_col_name, MAX_VAR_NAME_LENGTH, + "$%s_%s", var->name, fields[i].name); + /* Convert characters not allowed in variable names to '_' */ + for (j= 1; j < length; j++) + { + if (!my_isvar(charset_info,var_col_name[j])) + var_col_name[j]= '_'; + } + var_set(var_col_name, var_col_name + length, + row[i], row[i] + lengths[i]); +#endif + /* Add column to tab separated string */ + dynstr_append_mem(&result, row[i], lengths[i]); + } + dynstr_append_mem(&result, "\t", 1); + } + end= result.str + result.length-1; + eval_expr(var, result.str, (const char**) &end); + dynstr_free(&result); + } + else + eval_expr(var, "", 0); + + mysql_free_result(res); + DBUG_VOID_RETURN; +} + + +void var_copy(VAR *dest, VAR *src) +{ + dest->int_val= src->int_val; + dest->int_dirty= src->int_dirty; + + /* Alloc/realloc data for str_val in dest */ + if (dest->alloced_len < src->alloced_len && + !(dest->str_val= dest->str_val + ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) + : my_malloc(src->alloced_len, MYF(MY_WME)))) + die("Out of memory"); + else + dest->alloced_len= src->alloced_len; + + /* Copy str_val data to dest */ + dest->str_val_len= src->str_val_len; + if (src->str_val_len) + memcpy(dest->str_val, src->str_val, src->str_val_len); +} + + +void eval_expr(VAR *v, const char *p, const char **p_end) +{ + static int MIN_VAR_ALLOC= 32; /* MASV why 32? */ + VAR *vp; + if (*p == '$') + { + if ((vp= var_get(p, p_end, 0, 0))) + { + var_copy(v, vp); + return; + } + } + else if (*p == '`') + { + var_query_set(v, p, p_end); + } + else + { + int new_val_len = (p_end && *p_end) ? + (int) (*p_end - p) : (int) strlen(p); + if (new_val_len + 1 >= v->alloced_len) + { + v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ? + MIN_VAR_ALLOC : new_val_len + 1; + if (!(v->str_val = + v->str_val ? my_realloc(v->str_val, v->alloced_len+1, + MYF(MY_WME)) : + my_malloc(v->alloced_len+1, MYF(MY_WME)))) + die("Out of memory"); + } + 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); + v->int_dirty=0; + } + return; } @@ -988,103 +1392,53 @@ int open_file(const char *name) /* - Check for unexpected "junk" after the end of query - This is normally caused by missing delimiters -*/ - -int check_eol_junk(const char *eol) -{ - const char *p= eol; - DBUG_ENTER("check_eol_junk"); - DBUG_PRINT("enter", ("eol: %s", eol)); - /* Remove all spacing chars except new line */ - while (*p && my_isspace(charset_info, *p) && (*p != '\n')) - p++; - - /* Check for extra delimiter */ - if (*p && !strncmp(p, delimiter, delimiter_length)) - die("Extra delimiter \"%s\" found", delimiter); - - /* Allow trailing # comment */ - if (*p && *p != '#') - { - if (*p == '\n') - die("Missing delimiter"); - die("End of line junk detected: \"%s\"", p); - } - DBUG_RETURN(0); -} - - -/* ugly long name, but we are following the convention */ -int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused))) -{ - MYSQL* mysql = &cur_con->mysql; - for (;;) - { - MYSQL_RES *res; - MYSQL_ROW row; - int done; - LINT_INIT(res); - - if (mysql_query(mysql,"show status like 'Slave_running'") || - !(res=mysql_store_result(mysql))) - die("Query failed while probing slave for stop: %s", - mysql_error(mysql)); - if (!(row=mysql_fetch_row(res)) || !row[1]) - { - mysql_free_result(res); - die("Strange result from query while probing slave for stop"); - } - done = !strcmp(row[1],"OFF"); - mysql_free_result(res); - if (done) - break; - my_sleep(SLAVE_POLL_INTERVAL); - } - return 0; -} - - -/* Source and execute the given file SYNOPSIS - do_source() - query called command + do_source() + query called command DESCRIPTION - source <file_name> + source <file_name> - Open the file <file_name> and execute it + Open the file <file_name> and execute it */ -int do_source(struct st_query *query) +void do_source(struct st_command *command) { - char *p= query->first_argument, *name; - if (!*p) - die("Missing file name in source"); - name= p; - while (*p && !my_isspace(charset_info,*p)) - p++; - if (*p) - *p++= 0; - query->last_argument= p; + DYNAMIC_STRING ds_filename; + const struct command_arg source_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to source" + }; + DBUG_ENTER("do_source"); + + check_command_args(command, command->first_argument, source_args, + sizeof(source_args)/sizeof(struct command_arg), + ' '); + /* - If this file has already been sourced, don't source it again. - It's already available in the q_lines cache. + If this file has already been sourced, don't source it again. + It's already available in the q_lines cache. */ if (parser.current_line < (parser.read_lines - 1)) - return 0; - return open_file(name); + ; /* Do nothing */ + else + { + DBUG_PRINT("info", ("sourcing file: %s", ds_filename.str)); + open_file(ds_filename.str); + } + + dynstr_free(&ds_filename); + return; } + #ifdef __WIN__ -/* Variables used for temuprary sh files used for emulating Unix on Windows */ +/* Variables used for temporary sh files used for emulating Unix on Windows */ char tmp_sh_name[64], tmp_sh_cmd[70]; -static void init_tmp_sh_file() +void init_tmp_sh_file() { /* Format a name for the tmp sh file that is unique for this process */ my_snprintf(tmp_sh_name, sizeof(tmp_sh_name), "tmp_%d.sh", getpid()); @@ -1092,13 +1446,15 @@ static void init_tmp_sh_file() my_snprintf(tmp_sh_cmd, sizeof(tmp_sh_cmd), "sh %s", tmp_sh_name); } -static void free_tmp_sh_file() + +void free_tmp_sh_file() { my_delete(tmp_sh_name, MYF(0)); } #endif -FILE* my_popen(DYNAMIC_STRING* ds_cmd, const char* mode) + +FILE* my_popen(DYNAMIC_STRING *ds_cmd, const char *mode) { #ifdef __WIN__ /* Dump the command into a sh script file and execute with popen */ @@ -1114,49 +1470,49 @@ FILE* my_popen(DYNAMIC_STRING* ds_cmd, const char* mode) Execute given command. SYNOPSIS - do_exec() - query called command + do_exec() + query called command DESCRIPTION - exec <command> + exec <command> - Execute the text between exec and end of line in a subprocess. - The error code returned from the subprocess is checked against the - expected error array, previously set with the --error command. - It can thus be used to execute a command that shall fail. + Execute the text between exec and end of line in a subprocess. + The error code returned from the subprocess is checked against the + expected error array, previously set with the --error command. + It can thus be used to execute a command that shall fail. NOTE - Although mysqltest is executed from cygwin shell, the command will be - executed in "cmd.exe". Thus commands like "rm" etc can NOT be used, use - system for those commands. + Although mysqltest is executed from cygwin shell, the command will be + executed in "cmd.exe". Thus commands like "rm" etc can NOT be used, use + system for those commands. */ -static void do_exec(struct st_query *query) +void do_exec(struct st_command *command) { int error; char buf[1024]; FILE *res_file; - char *cmd= query->first_argument; + char *cmd= command->first_argument; DYNAMIC_STRING ds_cmd; DBUG_ENTER("do_exec"); DBUG_PRINT("enter", ("cmd: '%s'", cmd)); + /* Skip leading space */ while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) die("Missing argument in exec"); - query->last_argument= query->end; + command->last_argument= command->end; - init_dynamic_string(&ds_cmd, 0, strlen(cmd)+256, 256); + init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256); /* Eval the command, thus replacing all environment variables */ - do_eval(&ds_cmd, cmd, TRUE); - cmd= ds_cmd.str; + do_eval(&ds_cmd, cmd, command->end, TRUE); DBUG_PRINT("info", ("Executing '%s' as '%s'", - query->first_argument, cmd)); + command->first_argument, cmd)); - if (!(res_file= my_popen(&ds_cmd, "r")) && query->abort_on_error) - die("popen(\"%s\", \"r\") failed", query->first_argument); + if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error) + die("popen(\"%s\", \"r\") failed", command->first_argument); while (fgets(buf, sizeof(buf), res_file)) { @@ -1176,229 +1532,70 @@ static void do_exec(struct st_query *query) uint status= WEXITSTATUS(error), i; my_bool ok= 0; - if (query->abort_on_error) - die("command \"%s\" failed", query->first_argument); + if (command->abort_on_error) + die("command \"%s\" failed", command->first_argument); DBUG_PRINT("info", ("error: %d, status: %d", error, status)); - for (i= 0; i < query->expected_errors; i++) + for (i= 0; i < command->expected_errors.count; i++) { DBUG_PRINT("info", ("expected error: %d", - query->expected_errno[i].code.errnum)); - if ((query->expected_errno[i].type == ERR_ERRNO) && - (query->expected_errno[i].code.errnum == status)) + command->expected_errors.err[i].code.errnum)); + if ((command->expected_errors.err[i].type == ERR_ERRNO) && + (command->expected_errors.err[i].code.errnum == status)) { ok= 1; DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d", - query->first_argument, status)); + command->first_argument, status)); } } if (!ok) die("command \"%s\" failed with wrong error: %d", - query->first_argument, status); + command->first_argument, status); } - else if (query->expected_errno[0].type == ERR_ERRNO && - query->expected_errno[0].code.errnum != 0) + 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...", - query->first_argument, query->expected_errno[0].code.errnum); + command->first_argument, command->expected_errors.err[0].code.errnum); } - free_replace(); + dynstr_free(&ds_cmd); DBUG_VOID_RETURN; } -/* - Set variable from the result of a query - - SYNOPSIS - var_query_set() - var variable to set from query - query start of query string to execute - query_end end of the query string to execute - - - DESCRIPTION - let @<var_name> = `<query>` - - Execute the query and assign the first row of result to var as - a tab separated strings - - Also assign each column of the result set to - variable "$<var_name>_<column_name>" - Thus the tab separated output can be read from $<var_name> and - and each individual column can be read as $<var_name>_<col_name> - -*/ - -int var_query_set(VAR* var, const char *query, const char** query_end) -{ - char* end = (char*)((query_end && *query_end) ? - *query_end : query + strlen(query)); - MYSQL_RES *res; - MYSQL_ROW row; - MYSQL* mysql = &cur_con->mysql; - DBUG_ENTER("var_query_set"); - LINT_INIT(res); - - while (end > query && *end != '`') - --end; - if (query == end) - die("Syntax error in query, missing '`'"); - ++query; - - if (mysql_real_query(mysql, query, (int)(end - query)) || - !(res = mysql_store_result(mysql))) - { - *end = 0; - die("Error running query '%s': %d: %s", query, - mysql_errno(mysql) ,mysql_error(mysql)); - } - - if ((row = mysql_fetch_row(res)) && row[0]) - { - /* - Concatenate all row results with tab in between to allow us to work - with results from many columns (for example from SHOW VARIABLES) - */ - DYNAMIC_STRING result; - uint i; - ulong *lengths; - char *end; -#ifdef NOT_YET - MYSQL_FIELD *fields= mysql_fetch_fields(res); -#endif - - init_dynamic_string(&result, "", 16384, 65536); - lengths= mysql_fetch_lengths(res); - for (i=0; i < mysql_num_fields(res); i++) - { - if (row[0]) - { -#ifdef NOT_YET - /* Add to <var_name>_<col_name> */ - uint j; - char var_col_name[MAX_VAR_NAME]; - uint length= snprintf(var_col_name, MAX_VAR_NAME, - "$%s_%s", var->name, fields[i].name); - /* Convert characters not allowed in variable names to '_' */ - for (j= 1; j < length; j++) - { - if (!my_isvar(charset_info,var_col_name[j])) - var_col_name[j]= '_'; - } - var_set(var_col_name, var_col_name + length, - row[i], row[i] + lengths[i]); -#endif - /* Add column to tab separated string */ - dynstr_append_mem(&result, row[i], lengths[i]); - } - dynstr_append_mem(&result, "\t", 1); - } - end= result.str + result.length-1; - eval_expr(var, result.str, (const char**) &end); - dynstr_free(&result); - } - else - eval_expr(var, "", 0); - - mysql_free_result(res); - DBUG_RETURN(0); -} - -void var_copy(VAR *dest, VAR *src) -{ - dest->int_val= src->int_val; - dest->int_dirty= src->int_dirty; - - /* Alloc/realloc data for str_val in dest */ - if (dest->alloced_len < src->alloced_len && - !(dest->str_val= dest->str_val - ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) - : my_malloc(src->alloced_len, MYF(MY_WME)))) - die("Out of memory"); - else - dest->alloced_len= src->alloced_len; - - /* Copy str_val data to dest */ - dest->str_val_len= src->str_val_len; - if (src->str_val_len) - memcpy(dest->str_val, src->str_val, src->str_val_len); -} - -int eval_expr(VAR* v, const char *p, const char** p_end) -{ - VAR* vp; - if (*p == '$') - { - if ((vp = var_get(p,p_end,0,0))) - { - var_copy(v, vp); - return 0; - } - } - else if (*p == '`') - { - return var_query_set(v, p, p_end); - } - else - { - int new_val_len = (p_end && *p_end) ? - (int) (*p_end - p) : (int) strlen(p); - if (new_val_len + 1 >= v->alloced_len) - { - v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ? - MIN_VAR_ALLOC : new_val_len + 1; - if (!(v->str_val = - v->str_val ? my_realloc(v->str_val, v->alloced_len+1, - MYF(MY_WME)) : - my_malloc(v->alloced_len+1, MYF(MY_WME)))) - die("Out of memory"); - } - 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); - v->int_dirty=0; - return 0; - } - - die("Invalid expr: %s", p); - return 1; -} - - enum enum_operator { DO_DEC, DO_INC }; + /* Decrease or increase the value of a variable SYNOPSIS - do_modify_var() - query called command - operator operation to perform on the var + do_modify_var() + query called command + operator operation to perform on the var DESCRIPTION - dec $var_name - inc $var_name + dec $var_name + inc $var_name */ -int do_modify_var(struct st_query *query, +int do_modify_var(struct st_command *command, enum enum_operator operator) { - const char *p= query->first_argument; + const char *p= command->first_argument; VAR* v; if (!*p) - die("Missing argument to %.*s", query->first_word_len, query->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 $)", - query->first_word_len, query->query); + command->first_word_len, command->query); v= var_get(p, &p, 1, 0); switch (operator) { case DO_DEC: @@ -1412,7 +1609,7 @@ int do_modify_var(struct st_query *query, break; } v->int_dirty= 1; - query->last_argument= (char*)++p; + command->last_argument= (char*)++p; return 0; } @@ -1421,10 +1618,10 @@ int do_modify_var(struct st_query *query, Wrapper for 'system' function NOTE - If mysqltest is executed from cygwin shell, the command will be - executed in the "windows command interpreter" cmd.exe and we prepend "sh" - to make it be executed by cygwins "bash". Thus commands like "rm", - "mkdir" as well as shellscripts can executed by "system" in Windows. + If mysqltest is executed from cygwin shell, the command will be + executed in the "windows command interpreter" cmd.exe and we prepend "sh" + to make it be executed by cygwins "bash". Thus commands like "rm", + "mkdir" as well as shellscripts can executed by "system" in Windows. */ @@ -1441,20 +1638,19 @@ int my_system(DYNAMIC_STRING* ds_cmd) /* - SYNOPSIS do_system - command called command + command called command DESCRIPTION - system <command> + system <command> - Eval the query to expand any $variables in the command. - Execute the command with the "system" command. + Eval the query to expand any $variables in the command. + Execute the command with the "system" command. */ -void do_system(struct st_query *command) +void do_system(struct st_command *command) { DYNAMIC_STRING ds_cmd; DBUG_ENTER("do_system"); @@ -1462,10 +1658,10 @@ void do_system(struct st_query *command) if (strlen(command->first_argument) == 0) die("Missing arguments to system, nothing to do!"); - init_dynamic_string(&ds_cmd, 0, strlen(command->first_argument) + 64, 256); + init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256); /* Eval the system command, thus replacing all environment variables */ - do_eval(&ds_cmd, command->first_argument, TRUE); + do_eval(&ds_cmd, command->first_argument, command->end, TRUE); DBUG_PRINT("info", ("running system command '%s' as '%s'", command->first_argument, ds_cmd.str)); @@ -1487,50 +1683,375 @@ void do_system(struct st_query *command) /* + SYNOPSIS + do_remove_file + command called command + + DESCRIPTION + remove_file <file_name> + Remove the file <file_name> +*/ + +void do_remove_file(struct st_command *command) +{ + int error; + DYNAMIC_STRING ds_filename; + const struct command_arg rm_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" + }; + DBUG_ENTER("do_remove_file"); + + check_command_args(command, command->first_argument, + rm_args, sizeof(rm_args)/sizeof(struct command_arg), + ' '); + + DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); + error= my_delete(ds_filename.str, MYF(0)) != 0; + handle_command_error(command, error); + dynstr_free(&ds_filename); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_copy_file + command command handle + + DESCRIPTION + copy_file <from_file> <to_file> + Copy <from_file> to <to_file> + + NOTE! Will fail if <to_file> exists +*/ + +void do_copy_file(struct st_command *command) +{ + int error; + DYNAMIC_STRING ds_from_file; + DYNAMIC_STRING ds_to_file; + const struct command_arg copy_file_args[] = { + "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from", + "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" + }; + DBUG_ENTER("do_copy_file"); + + check_command_args(command, command->first_argument, + copy_file_args, + sizeof(copy_file_args)/sizeof(struct command_arg), + ' '); + + DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); + error= (my_copy(ds_from_file.str, ds_to_file.str, + MYF(MY_DONT_OVERWRITE_FILE)) != 0); + handle_command_error(command, error); + dynstr_free(&ds_from_file); + dynstr_free(&ds_to_file); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_file_exists + command called command + + DESCRIPTION + fiile_exist <file_name> + Check if file <file_name> exists +*/ + +void do_file_exist(struct st_command *command) +{ + int error; + DYNAMIC_STRING ds_filename; + const struct command_arg file_exist_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" + }; + DBUG_ENTER("do_file_exist"); + + check_command_args(command, command->first_argument, + file_exist_args, + sizeof(file_exist_args)/sizeof(struct command_arg), + ' '); + + DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str)); + error= (access(ds_filename.str, F_OK) != 0); + handle_command_error(command, error); + dynstr_free(&ds_filename); + DBUG_VOID_RETURN; +} + + +/* + Read characters from line buffer or file. This is needed to allow + my_ungetc() to buffer MAX_DELIMITER_LENGTH characters for a file + + NOTE: + This works as long as one doesn't change files (with 'source file_name') + when there is things pushed into the buffer. This should however not + happen for any tests in the test suite. +*/ + +int my_getc(FILE *file) +{ + if (line_buffer_pos == line_buffer) + return fgetc(file); + return *--line_buffer_pos; +} + + +void my_ungetc(int c) +{ + *line_buffer_pos++= (char) c; +} + + +void read_until_delimiter(DYNAMIC_STRING *ds, + DYNAMIC_STRING *ds_delimiter) +{ + int c; + DBUG_ENTER("read_until_delimiter"); + DBUG_PRINT("enter", ("delimiter: %s, length: %d", + ds_delimiter->str, ds_delimiter->length)); + + if (ds_delimiter->length > MAX_DELIMITER_LENGTH) + die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH); + + /* Read from file until delimiter is found */ + while (1) + { + c= my_getc(cur_file->file); + + if (c == '\n') + cur_file->lineno++; + + if (feof(cur_file->file)) + die("End of file encountered before '%s' delimiter was found", + ds_delimiter->str); + + if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length)) + { + DBUG_PRINT("exit", ("Found delimiter '%s'", ds_delimiter->str)); + break; + } + dynstr_append_mem(ds, (const char*)&c, 1); + } + DBUG_PRINT("exit", ("ds: %s", ds->str)); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_write_file + command called command + + DESCRIPTION + write_file <file_name> [<delimiter>]; + <what to write line 1> + <...> + < what to write line n> + EOF + + --write_file <file_name>; + <what to write line 1> + <...> + < what to write line n> + EOF + + Write everything between the "write_file" command and 'delimiter' + to "file_name" + + NOTE! Overwrites existing file + + Default <delimiter> is EOF + +*/ + +void do_write_file(struct st_command *command) +{ + DYNAMIC_STRING ds_content; + DYNAMIC_STRING ds_filename; + DYNAMIC_STRING ds_delimiter; + const struct command_arg write_file_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to write to", + "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" + }; + DBUG_ENTER("do_write_file"); + + check_command_args(command, + command->first_argument, + write_file_args, + sizeof(write_file_args)/sizeof(struct command_arg), + ' '); + + /* If no delimiter was provided, use EOF */ + if (ds_delimiter.length == 0) + dynstr_set(&ds_delimiter, "EOF"); + + init_dynamic_string(&ds_content, "", 1024, 1024); + read_until_delimiter(&ds_content, &ds_delimiter); + DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); + str_to_file(ds_filename.str, ds_content.str, ds_content.length); + dynstr_free(&ds_content); + dynstr_free(&ds_filename); + dynstr_free(&ds_delimiter); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_perl + command command handle + + DESCRIPTION + perl [<delimiter>]; + <perlscript line 1> + <...> + <perlscript line n> + EOF + + Execute everything after "perl" until <delimiter> as perl. + Useful for doing more advanced things + but still being able to execute it on all platforms. + + Default <delimiter> is EOF +*/ + +void do_perl(struct st_command *command) +{ + int error; + char buf[FN_REFLEN]; + FILE *res_file; + DYNAMIC_STRING ds_script; + DYNAMIC_STRING ds_delimiter; + const struct command_arg perl_args[] = { + "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" + }; + DBUG_ENTER("do_perl"); + + check_command_args(command, + command->first_argument, + perl_args, + sizeof(perl_args)/sizeof(struct command_arg), + ' '); + + /* If no delimiter was provided, use EOF */ + if (ds_delimiter.length == 0) + dynstr_set(&ds_delimiter, "EOF"); + + init_dynamic_string(&ds_script, "", 1024, 1024); + read_until_delimiter(&ds_script, &ds_delimiter); + + DBUG_PRINT("info", ("Executing perl: %s", ds_script.str)); + + /* Format a name for a tmp .pl file that is unique for this process */ + my_snprintf(buf, sizeof(buf), "%s/tmp/tmp_%d.pl", + getenv("MYSQLTEST_VARDIR"), getpid()); + str_to_file(buf, ds_script.str, ds_script.length); + + /* Format the perl <filename> command */ + my_snprintf(buf, sizeof(buf), "perl %s/tmp/tmp_%d.pl", + getenv("MYSQLTEST_VARDIR"), getpid()); + + if (!(res_file= popen(buf, "r")) && command->abort_on_error) + die("popen(\"%s\", \"r\") failed", buf); + + while (fgets(buf, sizeof(buf), res_file)) + { + if (disable_result_log) + { + buf[strlen(buf)-1]=0; + DBUG_PRINT("exec_result",("%s", buf)); + } + else + { + replace_dynstr_append(&ds_res, buf); + } + } + error= pclose(res_file); + handle_command_error(command, WEXITSTATUS(error)); + dynstr_free(&ds_script); + dynstr_free(&ds_delimiter); + DBUG_VOID_RETURN; +} + + +/* Print the content between echo and <delimiter> to result file. Evaluate all variables in the string before printing, allow for variable names to be escaped using \ SYNOPSIS - do_echo() - q called command + do_echo() + command called command DESCRIPTION - echo text - Print the text after echo until end of command to result file + echo text + Print the text after echo until end of command to result file - echo $<var_name> - Print the content of the variable <var_name> to result file + echo $<var_name> + Print the content of the variable <var_name> to result file - echo Some text $<var_name> - Print "Some text" plus the content of the variable <var_name> to - result file + echo Some text $<var_name> + Print "Some text" plus the content of the variable <var_name> to + result file - echo Some text \$<var_name> - Print "Some text" plus $<var_name> to result file + echo Some text \$<var_name> + Print "Some text" plus $<var_name> to result file */ -int do_echo(struct st_query *command) +int do_echo(struct st_command *command) { - DYNAMIC_STRING *ds, ds_echo; + DYNAMIC_STRING ds_echo; - ds= &ds_res; - - init_dynamic_string(&ds_echo, "", 256, 256); - do_eval(&ds_echo, command->first_argument, FALSE); - dynstr_append_mem(ds, ds_echo.str, ds_echo.length); - dynstr_append_mem(ds, "\n", 1); + init_dynamic_string(&ds_echo, "", command->query_len, 256); + do_eval(&ds_echo, command->first_argument, command->end, FALSE); + dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length); + dynstr_append_mem(&ds_res, "\n", 1); dynstr_free(&ds_echo); command->last_argument= command->end; return(0); } -int do_sync_with_master2(long offset) +void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused))) { - MYSQL_RES* res; + static int SLAVE_POLL_INTERVAL= 300000; + MYSQL* mysql = &cur_con->mysql; + for (;;) + { + MYSQL_RES *res; + MYSQL_ROW row; + int done; + LINT_INIT(res); + + if (mysql_query(mysql,"show status like 'Slave_running'") || + !(res=mysql_store_result(mysql))) + die("Query failed while probing slave for stop: %s", + mysql_error(mysql)); + if (!(row=mysql_fetch_row(res)) || !row[1]) + { + mysql_free_result(res); + die("Strange result from query while probing slave for stop"); + } + done = !strcmp(row[1],"OFF"); + mysql_free_result(res); + if (done) + break; + my_sleep(SLAVE_POLL_INTERVAL); + } + return; +} + + +void do_sync_with_master2(long offset) +{ + MYSQL_RES *res; MYSQL_ROW row; - MYSQL* mysql= &cur_con->mysql; + MYSQL *mysql= &cur_con->mysql; char query_buf[FN_REFLEN+128]; int tries= 0; int rpl_parse; @@ -1546,7 +2067,7 @@ int do_sync_with_master2(long offset) wait_for_position: if (mysql_query(mysql, query_buf)) - die("failed in %s: %d: %s", query_buf, mysql_errno(mysql), + die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql), mysql_error(mysql)); if (!(res= mysql_store_result(mysql))) @@ -1569,13 +2090,14 @@ wait_for_position: if (rpl_parse) mysql_enable_rpl_parse(mysql); - return 0; + return; } -int do_sync_with_master(struct st_query *query) + +void do_sync_with_master(struct st_command *command) { long offset= 0; - char *p= query->first_argument; + char *p= command->first_argument; const char *offset_start= p; if (*offset_start) { @@ -1584,20 +2106,22 @@ int do_sync_with_master(struct st_query *query) if(*p && !my_isspace(charset_info, *p)) die("Invalid integer argument \"%s\"", offset_start); - query->last_argument= p; + command->last_argument= p; } - return do_sync_with_master2(offset); + do_sync_with_master2(offset); + return; } + /* when ndb binlog is on, this call will wait until last updated epoch (locally in the mysqld) has been received into the binlog */ int do_save_master_pos() { - MYSQL_RES* res; + MYSQL_RES *res; MYSQL_ROW row; - MYSQL* mysql = &cur_con->mysql; + MYSQL *mysql = &cur_con->mysql; const char *query; int rpl_parse; @@ -1606,19 +2130,18 @@ int do_save_master_pos() #ifdef HAVE_NDB_BINLOG /* - Wait for ndb binlog to be up-to-date with all changes - done on the local mysql server + Wait for ndb binlog to be up-to-date with all changes + done on the local mysql server */ { ulong have_ndbcluster; if (mysql_query(mysql, query= "show variables like 'have_ndbcluster'")) - die("At line %u: failed in %s: %d: %s", start_lineno, query, + die("'%s' failed: %d %s", query, mysql_errno(mysql), mysql_error(mysql)); if (!(res= mysql_store_result(mysql))) - die("line %u: mysql_store_result() retuned NULL for '%s'", start_lineno, - query); + die("mysql_store_result() returned NULL for '%s'", query); if (!(row= mysql_fetch_row(res))) - die("line %u: empty result in %s", start_lineno, query); + die("Query '%s' returned empty result", query); have_ndbcluster= strcmp("YES", row[1]) == 0; mysql_free_result(res); @@ -1626,7 +2149,7 @@ int do_save_master_pos() if (have_ndbcluster) { ulonglong start_epoch= 0, applied_epoch= 0, - latest_epoch=0, latest_trans_epoch=0, + latest_epoch=0, latest_trans_epoch=0, latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0, latest_applied_binlog_epoch= 0; int count= 0; @@ -1647,11 +2170,10 @@ int do_save_master_pos() if (count) sleep(1); if (mysql_query(mysql, query= "show engine ndb status")) - die("At line %u: failed in '%s': %d: %s", start_lineno, query, + die("failed in '%s': %d %s", query, mysql_errno(mysql), mysql_error(mysql)); if (!(res= mysql_store_result(mysql))) - die("line %u: mysql_store_result() retuned NULL for '%s'", - start_lineno, query); + die("mysql_store_result() returned NULL for '%s'", query); while ((row= mysql_fetch_row(res))) { if (strcmp(row[1], binlog) == 0) @@ -1668,8 +2190,8 @@ int do_save_master_pos() latest_epoch= strtoull(status, (char**) 0, 10); } else - die("line %u: result does not contain '%s' in '%s'", - start_lineno, latest_epoch_str, query); + die("result does not contain '%s' in '%s'", + latest_epoch_str, query); /* latest_trans_epoch */ while (*status && strncmp(status, latest_trans_epoch_str, sizeof(latest_trans_epoch_str)-1)) @@ -1680,10 +2202,10 @@ int do_save_master_pos() latest_trans_epoch= strtoull(status, (char**) 0, 10); } else - die("line %u: result does not contain '%s' in '%s'", - start_lineno, latest_trans_epoch_str, query); + die("result does not contain '%s' in '%s'", + latest_trans_epoch_str, query); /* latest_received_binlog_epoch */ - while (*status && + while (*status && strncmp(status, latest_received_binlog_epoch_str, sizeof(latest_received_binlog_epoch_str)-1)) status++; @@ -1693,10 +2215,10 @@ int do_save_master_pos() latest_received_binlog_epoch= strtoull(status, (char**) 0, 10); } else - die("line %u: result does not contain '%s' in '%s'", - start_lineno, latest_received_binlog_epoch_str, query); + die("result does not contain '%s' in '%s'", + latest_received_binlog_epoch_str, query); /* latest_handled_binlog */ - while (*status && + while (*status && strncmp(status, latest_handled_binlog_epoch_str, sizeof(latest_handled_binlog_epoch_str)-1)) status++; @@ -1706,10 +2228,10 @@ int do_save_master_pos() latest_handled_binlog_epoch= strtoull(status, (char**) 0, 10); } else - die("line %u: result does not contain '%s' in '%s'", - start_lineno, latest_handled_binlog_epoch_str, query); + die("result does not contain '%s' in '%s'", + latest_handled_binlog_epoch_str, query); /* latest_applied_binlog_epoch */ - while (*status && + while (*status && strncmp(status, latest_applied_binlog_epoch_str, sizeof(latest_applied_binlog_epoch_str)-1)) status++; @@ -1719,16 +2241,16 @@ int do_save_master_pos() latest_applied_binlog_epoch= strtoull(status, (char**) 0, 10); } else - die("line %u: result does not contain '%s' in '%s'", - start_lineno, latest_applied_binlog_epoch_str, query); + die("result does not contain '%s' in '%s'", + latest_applied_binlog_epoch_str, query); if (count == 0) start_epoch= latest_trans_epoch; break; } } if (!row) - die("line %u: result does not contain '%s' in '%s'", - start_lineno, binlog, query); + die("result does not contain '%s' in '%s'", + binlog, query); if (latest_applied_binlog_epoch > applied_epoch) count= 0; applied_epoch= latest_applied_binlog_epoch; @@ -1745,7 +2267,7 @@ int do_save_master_pos() } #endif if (mysql_query(mysql, query= "show master status")) - die("failed in show master status: %d: %s", + die("failed in 'show master status': %d %s", mysql_errno(mysql), mysql_error(mysql)); if (!(res = mysql_store_result(mysql))) @@ -1767,28 +2289,29 @@ int do_save_master_pos() Assign the variable <var_name> with <var_val> SYNOPSIS - do_let() - query called command + do_let() + query called command DESCRIPTION - let $<var_name>=<var_val><delimiter> + let $<var_name>=<var_val><delimiter> - <var_name> - is the string string found between the $ and = - <var_val> - is the content between the = and <delimiter>, it may span - multiple line and contain any characters except <delimiter> - <delimiter> - is a string containing of one or more chars, default is ; + <var_name> - is the string string found between the $ and = + <var_val> - is the content between the = and <delimiter>, it may span + multiple line and contain any characters except <delimiter> + <delimiter> - is a string containing of one or more chars, default is ; RETURN VALUES - Program will die if error detected + Program will die if error detected */ -int do_let(struct st_query *query) +void do_let(struct st_command *command) { - int ret; - char *p= query->first_argument; + char *p= command->first_argument; char *var_name, *var_name_end; DYNAMIC_STRING let_rhs_expr; + DBUG_ENTER("do_let"); + init_dynamic_string(&let_rhs_expr, "", 512, 2048); /* Find <var_name> */ @@ -1810,34 +2333,18 @@ int do_let(struct st_query *query) while (*p && my_isspace(charset_info,*p)) p++; - do_eval(&let_rhs_expr, p, FALSE); + do_eval(&let_rhs_expr, p, command->end, FALSE); - query->last_argument= query->end; + command->last_argument= command->end; /* Assign var_val to var_name */ - ret= var_set(var_name, var_name_end, let_rhs_expr.str, - (let_rhs_expr.str + let_rhs_expr.length)); + var_set(var_name, var_name_end, let_rhs_expr.str, + (let_rhs_expr.str + let_rhs_expr.length)); dynstr_free(&let_rhs_expr); - - return(ret); -} - - -/* - Store an integer (typically the returncode of the last SQL) - statement in the mysqltest builtin variable $mysql_errno, by - simulating of a user statement "let $mysql_errno= <integer>" -*/ - -int var_set_errno(int sql_errno) -{ - const char *var_name= "$mysql_errno"; - char var_val[21]; - uint length= my_sprintf(var_val, (var_val, "%d", sql_errno)); - return var_set(var_name, var_name + 12, var_val, var_val + length); + DBUG_VOID_RETURN; } -int do_rpl_probe(struct st_query *query __attribute__((unused))) +int do_rpl_probe(struct st_command *command __attribute__((unused))) { DBUG_ENTER("do_rpl_probe"); if (mysql_rpl_probe(&cur_con->mysql)) @@ -1846,14 +2353,14 @@ int do_rpl_probe(struct st_query *query __attribute__((unused))) } -int do_enable_rpl_parse(struct st_query *query __attribute__((unused))) +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_query *query __attribute__((unused))) +int do_disable_rpl_parse(struct st_command *command __attribute__((unused))) { mysql_disable_rpl_parse(&cur_con->mysql); return 0; @@ -1861,17 +2368,17 @@ int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) /* - Sleep the number of specifed seconds + Sleep the number of specified seconds SYNOPSIS - do_sleep() - q called command - real_sleep use the value from opt_sleep as number of seconds to sleep - if real_sleep is false + do_sleep() + q called command + real_sleep use the value from opt_sleep as number of seconds to sleep + if real_sleep is false DESCRIPTION - sleep <seconds> - real_sleep <seconds> + sleep <seconds> + real_sleep <seconds> The difference between the sleep and real_sleep commands is that sleep uses the delay from the --sleep command-line option if there is one. @@ -1882,26 +2389,26 @@ int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) used for cpu-independent delays. */ -int do_sleep(struct st_query *query, my_bool real_sleep) +int do_sleep(struct st_command *command, my_bool real_sleep) { int error= 0; - char *p= query->first_argument; - char *sleep_start, *sleep_end= query->end; + char *p= command->first_argument; + char *sleep_start, *sleep_end= command->end; double sleep_val; while (my_isspace(charset_info, *p)) p++; if (!*p) - die("Missing argument to %.*s", query->first_word_len, query->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)) - die("Invalid argument to %.*s \"%s\"", query->first_word_len, query->query, - query->first_argument); + die("Invalid argument to %.*s \"%s\"", command->first_word_len, + command->query,command->first_argument); sleep_val= my_strtod(sleep_start, &sleep_end, &error); if (error) - die("Invalid argument to %.*s \"%s\"", query->first_word_len, query->query, - query->first_argument); + die("Invalid argument to %.*s \"%s\"", command->first_word_len, + command->query, command->first_argument); /* Fixed sleep time selected by --sleep option */ if (opt_sleep >= 0 && !real_sleep) @@ -1910,13 +2417,15 @@ int do_sleep(struct st_query *query, my_bool real_sleep) DBUG_PRINT("info", ("sleep_val: %f", sleep_val)); if (sleep_val) my_sleep((ulong) (sleep_val * 1000000L)); - query->last_argument= sleep_end; + command->last_argument= sleep_end; return 0; } -static void get_file_name(char *filename, struct st_query *q) + +void do_get_file_name(struct st_command *command, + char* dest, uint dest_max_len) { - char *p= q->first_argument, *name; + char *p= command->first_argument, *name; if (!*p) die("Missing file name argument"); name= p; @@ -1924,13 +2433,14 @@ static void get_file_name(char *filename, struct st_query *q) p++; if (*p) *p++= 0; - q->last_argument= p; - strmake(filename, name, FN_REFLEN); + command->last_argument= p; + strmake(dest, name, dest_max_len); } -static void set_charset(struct st_query *q) + +void do_set_charset(struct st_command *command) { - char *charset_name= q->first_argument; + char *charset_name= command->first_argument; char *p; if (!charset_name || !*charset_name) @@ -1941,78 +2451,182 @@ static void set_charset(struct st_query *q) p++; if(*p) *p++= 0; - q->last_argument= p; + command->last_argument= p; charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME)); if (!charset_info) abort_not_supported_test("Test requires charset '%s'", charset_name); } -static uint get_errcodes(match_err *to,struct st_query *q) + +#if MYSQL_VERSION_ID >= 50000 +/* List of error names to error codes, available from 5.0 */ +typedef struct +{ + const char *name; + uint code; +} st_error; + +static st_error global_error_names[] = +{ +#include <mysqld_ername.h> + { 0, 0 } +}; + +uint get_errcode_from_name(char *error_name, char *error_end) { - char *p= q->first_argument; + /* SQL error as string */ + st_error *e= global_error_names; + + DBUG_ENTER("get_errcode_from_name"); + DBUG_PRINT("enter", ("error_name: %s", error_name)); + + /* Loop through the array of known error names */ + for (; e->name; e++) + { + /* + If we get a match, we need to check the length of the name we + matched against in case it was longer than what we are checking + (as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT). + */ + if (!strncmp(error_name, e->name, (int) (error_end - error_name)) && + (uint) strlen(e->name) == (uint) (error_end - error_name)) + { + DBUG_RETURN(e->code); + } + } + if (!e->name) + 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))) +{ + abort_not_in_this_version(); + return 0; /* Never reached */ +} +#endif + + + +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; - DBUG_ENTER("get_errcodes"); + DBUG_ENTER("do_get_errcodes"); if (!*p) - die("Missing argument in %s", q->query); + die("Missing argument(s) to 'error'"); do { + char *end; + + /* Skip leading spaces */ + while (*p && *p == ' ') + p++; + + /* Find end */ + end= p; + while (*end && *end != ',' && *end != ' ') + end++; + if (*p == 'S') { - /* SQLSTATE string */ - char *end= ++p + SQLSTATE_LENGTH; - char *to_ptr= to[count].code.sqlstate; + char *to_ptr= to->code.sqlstate; - for (; my_isalnum(charset_info, *p) && p != end; p++) - *to_ptr++= *p; - *to_ptr= 0; + /* + SQLSTATE string + - Must be SQLSTATE_LENGTH long + - May contain only digits[0-9] and _uppercase_ letters + */ + p++; /* Step past the S */ + if ((end - p) != SQLSTATE_LENGTH) + die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH); + + /* Check sqlstate string validity */ + while (*p && p < end) + { + if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p)) + *to_ptr++= *p++; + else + die("The sqlstate may only consist of digits[0-9] " \ + "and _uppercase_ letters"); + } - to[count].type= ERR_SQLSTATE; + *to_ptr= 0; + to->type= ERR_SQLSTATE; + DBUG_PRINT("info", ("ERR_SQLSTATE: %d", to->code.sqlstate)); + } + else if (*p == 's') + { + die("The sqlstate definition must start with an uppercase S"); } else if (*p == 'E') { - /* SQL error as string */ - st_error *e= global_error; - char *start= p++; + /* Error name string */ - for (; *p == '_' || my_isalnum(charset_info, *p); p++) - ; - for (; e->name; e++) - { - /* - If we get a match, we need to check the length of the name we - matched against in case it was longer than what we are checking - (as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT). - */ - if (!strncmp(start, e->name, (int) (p - start)) && - (uint) strlen(e->name) == (uint) (p - start)) - { - to[count].code.errnum= (uint) e->code; - to[count].type= ERR_ERRNO; - break; - } - } - if (!e->name) - die("Unknown SQL error '%s'", start); + DBUG_PRINT("info", ("Error name: %s", p)); + to->code.errnum= get_errcode_from_name(p, end); + to->type= ERR_ERRNO; + DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum)); + } + else if (*p == 'e') + { + die("The error name definition must start with an uppercase E"); } else { long val; + char *start= p; + /* Check that the string passed to str2int only contain digits */ + while (*p && p != end) + { + if (!my_isdigit(charset_info, *p)) + die("Invalid argument to error: '%s' - "\ + "the errno may only consist of digits[0-9]", + command->first_argument); + p++; + } - if (!(p= str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val))) - die("Invalid argument in %s", q->query); - to[count].code.errnum= (uint) val; - to[count].type= ERR_ERRNO; + /* Convert the sting to int */ + if (!str2int(start, 10, (long) INT_MIN, (long) INT_MAX, &val)) + die("Invalid argument to error: '%s'", command->first_argument); + + to->code.errnum= (uint) val; + to->type= ERR_ERRNO; + DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum)); } + to++; count++; - } while (*(p++) == ','); - q->last_argument= (p - 1); - to[count].type= ERR_EMPTY; /* End of data */ - DBUG_RETURN(count); + + if (count >= (sizeof(saved_expected_errors.err) / + sizeof(struct st_match_err))) + die("Too many errorcodes specified"); + + /* Set pointer to the end of the last error code */ + p= end; + + /* Find next ',' */ + while (*p && *p != ',') + p++; + + if (*p) + p++; /* Step past ',' */ + + } while (*p); + + command->last_argument= p; + to->type= ERR_EMPTY; /* End of data */ + + DBUG_PRINT("info", ("Expected errors: %d", count)); + saved_expected_errors.count= count; + DBUG_VOID_RETURN; } + /* Get a string; Return ptr to end of string Strings may be surrounded by " or ' @@ -2020,11 +2634,10 @@ static uint get_errcodes(match_err *to,struct st_query *q) If string is a '$variable', return the value of the variable. */ - -static char *get_string(char **to_ptr, char **from_ptr, - struct st_query *q) +char *get_string(char **to_ptr, char **from_ptr, + struct st_command *command) { - reg1 char c,sep; + char c, sep; char *to= *to_ptr, *from= *from_ptr, *start=to; DBUG_ENTER("get_string"); @@ -2070,7 +2683,7 @@ static char *get_string(char **to_ptr, char **from_ptr, *to++=c; } if (*from != ' ' && *from) - die("Wrong string argument in %s", q->query); + die("Wrong string argument in %s", command->query); while (my_isspace(charset_info,*from)) /* Point to next string */ from++; @@ -2093,282 +2706,25 @@ static char *get_string(char **to_ptr, char **from_ptr, DBUG_RETURN(start); } -/* - Finds the next (non-escaped) '/' in the expression. - (If the character '/' is needed, it can be escaped using '\'.) -*/ - -#define PARSE_REGEX_ARG \ - while (p < expr_end) \ - {\ - char c= *p;\ - if (c == '/')\ - {\ - if (last_c == '\\')\ - {\ - buf_p[-1]= '/';\ - }\ - else\ - {\ - *buf_p++ = 0;\ - break;\ - } \ - } \ - else\ - *buf_p++ = c;\ - \ - last_c= c;\ - p++;\ - } \ - -/* - Initializes the regular substitution expression to be used in the - result output of test. - - Returns: st_replace_regex struct with pairs of substitutions -*/ - -static struct st_replace_regex* init_replace_regex(char* expr) -{ - struct st_replace_regex* res; - char* buf,*expr_end; - char* p; - char* buf_p; - uint expr_len= strlen(expr); - char last_c = 0; - struct st_regex reg; - - /* my_malloc() will die on fail with MY_FAE */ - res=(struct st_replace_regex*)my_malloc( - sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME)); - my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128); - - buf= (char*)res + sizeof(*res); - expr_end= expr + expr_len; - p= expr; - buf_p= buf; - - /* for each regexp substitution statement */ - while (p < expr_end) - { - bzero(®,sizeof(reg)); - /* find the start of the statement */ - while (p < expr_end) - { - if (*p == '/') - break; - p++; - } - - if (p == expr_end || ++p == expr_end) - { - if (res->regex_arr.elements) - break; - else - goto err; - } - /* we found the start */ - reg.pattern= buf_p; - - /* Find first argument -- pattern string to be removed */ - PARSE_REGEX_ARG - - if (p == expr_end || ++p == expr_end) - goto err; - - /* buf_p now points to the replacement pattern terminated with \0 */ - reg.replace= buf_p; - - /* Find second argument -- replace string to replace pattern */ - PARSE_REGEX_ARG - - if (p == expr_end) - goto err; - - /* skip the ending '/' in the statement */ - p++; - - /* Check if we should do matching case insensitive */ - if (p < expr_end && *p == 'i') - reg.icase= 1; - - /* done parsing the statement, now place it in regex_arr */ - if (insert_dynamic(&res->regex_arr,(gptr) ®)) - die("Out of memory"); - } - res->odd_buf_len= res->even_buf_len= 8192; - res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE)); - res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE)); - res->buf= res->even_buf; - - return res; - -err: - my_free((gptr)res,0); - die("Error parsing replace_regex \"%s\"", expr); - return 0; -} - -/* - Execute all substitutions on val. - - Returns: true if substituition was made, false otherwise - Side-effect: Sets r->buf to be the buffer with all substitutions done. - - IN: - struct st_replace_regex* r - char* val - Out: - struct st_replace_regex* r - r->buf points at the resulting buffer - r->even_buf and r->odd_buf might have been reallocated - r->even_buf_len and r->odd_buf_len might have been changed - - TODO: at some point figure out if there is a way to do everything - in one pass -*/ - -static int multi_reg_replace(struct st_replace_regex* r,char* val) -{ - uint i; - char* in_buf, *out_buf; - int* buf_len_p; - - in_buf= val; - out_buf= r->even_buf; - buf_len_p= &r->even_buf_len; - r->buf= 0; - - /* For each substitution, do the replace */ - for (i= 0; i < r->regex_arr.elements; i++) - { - struct st_regex re; - char* save_out_buf= out_buf; - - get_dynamic(&r->regex_arr,(gptr)&re,i); - - if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace, - in_buf, re.icase)) - { - /* if the buffer has been reallocated, make adjustements */ - if (save_out_buf != out_buf) - { - if (save_out_buf == r->even_buf) - r->even_buf= out_buf; - else - r->odd_buf= out_buf; - } - - r->buf= out_buf; - if (in_buf == val) - in_buf= r->odd_buf; - - swap_variables(char*,in_buf,out_buf); - - buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len : - &r->odd_buf_len; - } - } - - return (r->buf == 0); -} - -/* - Parse the regular expression to be used in all result files - from now on. - - The syntax is --replace_regex /from/to/i /from/to/i ... - i means case-insensitive match. If omitted, the match is - case-sensitive - -*/ -static void get_replace_regex(struct st_query *q) -{ - char *expr= q->first_argument; - free_replace_regex(); - if (!(glob_replace_regex=init_replace_regex(expr))) - die("Could not init replace_regex"); - q->last_argument= q->end; -} - -/* - Get arguments for replace. The syntax is: - replace from to [from to ...] - Where each argument may be quoted with ' or " - A argument may also be a variable, in which case the value of the - variable is replaced. -*/ - -static void get_replace(struct st_query *q) +void set_reconnect(MYSQL* mysql, int val) { - uint i; - char *from= q->first_argument; - char *buff,*start; - char word_end_chars[256],*pos; - POINTER_ARRAY to_array,from_array; - DBUG_ENTER("get_replace"); - - free_replace(); - - bzero((char*) &to_array,sizeof(to_array)); - bzero((char*) &from_array,sizeof(from_array)); - if (!*from) - die("Missing argument in %s", q->query); - start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); - while (*from) - { - char *to=buff; - to=get_string(&buff, &from, q); - if (!*from) - die("Wrong number of arguments to replace_result in '%s'", q->query); - insert_pointer_name(&from_array,to); - to=get_string(&buff, &from, q); - insert_pointer_name(&to_array,to); - } - for (i=1,pos=word_end_chars ; i < 256 ; i++) - if (my_isspace(charset_info,i)) - *pos++= i; - *pos=0; /* End pointer */ - if (!(glob_replace=init_replace((char**) from_array.typelib.type_names, - (char**) to_array.typelib.type_names, - (uint) from_array.typelib.count, - word_end_chars))) - die("Can't initialize replace from '%s'", q->query); - free_pointer_array(&from_array); - free_pointer_array(&to_array); - my_free(start, MYF(0)); - q->last_argument= q->end; + my_bool reconnect= val; + DBUG_ENTER("set_reconnect"); + DBUG_PRINT("info", ("val: %d", val)); +#if MYSQL_VERSION_ID < 50000 + mysql->reconnect= reconnect; +#else + mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); +#endif DBUG_VOID_RETURN; } -static void free_replace_regex() -{ - if (glob_replace_regex) - { - 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((char*) glob_replace_regex,MYF(0)); - glob_replace_regex=0; - } -} - -void free_replace() -{ - DBUG_ENTER("free_replace"); - if (glob_replace) - { - my_free((char*) glob_replace,MYF(0)); - glob_replace=0; - } - DBUG_VOID_RETURN; -} - -struct connection * find_connection_by_name(const char *name) +struct st_connection * find_connection_by_name(const char *name) { - struct connection *con; - for (con= cons; con < next_con; con++) + struct st_connection *con; + for (con= connections; con < next_con; con++) { if (!strcmp(con->name, name)) { @@ -2390,10 +2746,10 @@ int select_connection_name(const char *name) } -int select_connection(struct st_query *query) +int select_connection(struct st_command *command) { char *name; - char *p= query->first_argument; + char *p= command->first_argument; DBUG_ENTER("select_connection"); if (!*p) @@ -2403,15 +2759,16 @@ int select_connection(struct st_query *query) p++; if (*p) *p++= 0; - query->last_argument= p; + command->last_argument= p; return select_connection_name(name); } -int close_connection(struct st_query *q) +void do_close_connection(struct st_command *command) { - char *p= q->first_argument, *name; - struct connection *con; + char *p= command->first_argument, *name; + struct st_connection *con; + DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("name: '%s'",p)); @@ -2423,13 +2780,17 @@ int close_connection(struct st_query *q) if (*p) *p++= 0; - q->last_argument= p; - for (con= cons; con < next_con; con++) + command->last_argument= p; + + /* Loop through connection pool for connection to close */ + for (con= connections; con < next_con; con++) { + DBUG_PRINT("info", ("con->name: %s", con->name)); if (!strcmp(con->name, name)) { + DBUG_PRINT("info", ("Closing connection %s", con->name)); #ifndef EMBEDDED_LIBRARY - if (q->type == Q_DIRTY_CLOSE) + if (command->type == Q_DIRTY_CLOSE) { if (con->mysql.net.vio) { @@ -2443,59 +2804,19 @@ int close_connection(struct st_query *q) mysql_close(con->util_mysql); con->util_mysql= 0; my_free(con->name, MYF(0)); + /* - When the connection is closed set name to "closed_connection" - to make it possible to reuse the connection name. - The connection slot will not be reused - */ + When the connection is closed set name to "closed_connection" + to make it possible to reuse the connection name. + The connection slot will not be reused + */ if (!(con->name = my_strdup("closed_connection", MYF(MY_WME)))) die("Out of memory"); - DBUG_RETURN(0); + + DBUG_VOID_RETURN; } } die("connection '%s' not found in connection pool", name); - DBUG_RETURN(1); /* Never reached */ -} - - -/* - This one now is a hack - we may want to improve in in the - future to handle quotes. For now we assume that anything that is not - a comma, a space or ) belongs to the argument. space is a chopper, comma or - ) are delimiters/terminators - - SYNOPSIS - safe_get_param - str - string to get param from - arg - pointer to string where result will be stored - msg - Message to display if param is not found - if msg is 0 this param is not required and param may be empty - - RETURNS - pointer to str after param - -*/ - -char* safe_get_param(char *str, char** arg, const char *msg) -{ - DBUG_ENTER("safe_get_param"); - if(!*str) - { - if (msg) - die(msg); - *arg= str; - DBUG_RETURN(str); - } - while (*str && my_isspace(charset_info,*str)) - str++; - *arg= str; - while (*str && *str != ',' && *str != ')') - str++; - if (msg && !*arg) - die(msg); - - *str++= 0; - DBUG_RETURN(str); } @@ -2503,54 +2824,60 @@ char* safe_get_param(char *str, char** arg, const char *msg) Connect to a server doing several retries if needed. SYNOPSIS - safe_connect() - con - connection structure to be used - host, user, pass, - connection parameters - db, port, sock + safe_connect() + con - connection structure to be used + host, user, pass, - connection parameters + db, port, sock NOTE - Sometimes in a test the client starts before - the server - to solve the problem, we try again - after some sleep if connection fails the first - time + Sometimes in a test the client starts before + the server - to solve the problem, we try again + after some sleep if connection fails the first + time - This function will try to connect to the given server - "opt_max_connect_retries" times and sleep "connection_retry_sleep" - seconds between attempts before finally giving up. - This helps in situation when the client starts - before the server (which happens sometimes). - It will ignore any errors during these retries. One should use - connect_n_handle_errors() if he expects a connection error and wants - handle as if it was an error from a usual statement. + This function will try to connect to the given server + "opt_max_connect_retries" times and sleep "connection_retry_sleep" + seconds between attempts before finally giving up. + This helps in situation when the client starts + before the server (which happens sometimes). + It will only ignore connection errors during these retries. - RETURN VALUE - 0 - success, non-0 - failure */ -int safe_connect(MYSQL* mysql, const char *host, const char *user, - const char *pass, const char *db, int port, const char *sock) +void safe_connect(MYSQL* mysql, const char *name, const char *host, + const char *user, const char *pass, const char *db, + int port, const char *sock) { - int con_error= 1; - my_bool reconnect= 1; + int failed_attempts= 0; static ulong connection_retry_sleep= 100000; /* Microseconds */ - int i; - for (i= 0; i < opt_max_connect_retries; i++) + + DBUG_ENTER("safe_connect"); + while(!mysql_real_connect(mysql, host,user, pass, db, port, sock, + CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS)) { - if (mysql_real_connect(mysql, host,user, pass, db, port, sock, - CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS)) + /* + Connect failed + + Only allow retry if this was an error indicating the server + could not be contacted + */ + + if (mysql_errno(mysql) == CR_CONNECTION_ERROR && + failed_attempts < opt_max_connect_retries) + my_sleep(connection_retry_sleep); + else { - con_error= 0; - break; + if (failed_attempts > 0) + die("Could not open connection '%s' after %d attempts: %d %s", name, + failed_attempts, mysql_errno(mysql), mysql_error(mysql)); + else + die("Could not open connection '%s': %d %s", name, + mysql_errno(mysql), mysql_error(mysql)); } - my_sleep(connection_retry_sleep); + failed_attempts++; } - /* - TODO: change this to 0 in future versions, but the 'kill' test relies on - existing behavior - */ - mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); - return con_error; + DBUG_VOID_RETURN; } @@ -2558,45 +2885,41 @@ int safe_connect(MYSQL* mysql, const char *host, const char *user, Connect to a server and handle connection errors in case they occur. SYNOPSIS - connect_n_handle_errors() - q - context of connect "query" (command) - con - connection structure to be used - host, user, pass, - connection parameters - db, port, sock - create_conn - out parameter, set to zero if connection was - not established and is not touched otherwise + connect_n_handle_errors() + q - context of connect "query" (command) + con - connection structure to be used + host, user, pass, - connection parameters + db, port, sock DESCRIPTION - This function will try to establish a connection to server and handle - possible errors in the same manner as if "connect" was usual SQL-statement - (If error is expected it will ignore it once it occurs and log the - "statement" to the query log). - Unlike safe_connect() it won't do several attempts. + This function will try to establish a connection to server and handle + possible errors in the same manner as if "connect" was usual SQL-statement + (If error is expected it will ignore it once it occurs and log the + "statement" to the query log). + Unlike safe_connect() it won't do several attempts. + + RETURN VALUES + 1 - Connected + 0 - Not connected - RETURN VALUE - 0 - success, non-0 - failure */ -int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, +int connect_n_handle_errors(struct st_command *command, + MYSQL* con, const char* host, const char* user, const char* pass, - const char* db, int port, const char* sock, - int* create_conn) + const char* db, int port, const char* sock) { DYNAMIC_STRING *ds; - my_bool reconnect= 1; - int error= 0; ds= &ds_res; - if (!disable_query_log) + /* Only log if an error is expected */ + if (!command->abort_on_error && + !disable_query_log) { /* - It is nice to have connect() statement logged in result file - in this case. - QQ: Should we do this only if we are expecting an error ? + Log the connect to result log */ - char port_buff[22]; /* This should be enough for any int */ - char *port_end; dynstr_append_mem(ds, "connect(", 8); replace_dynstr_append(ds, host); dynstr_append_mem(ds, ",", 1); @@ -2607,8 +2930,7 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, if (db) replace_dynstr_append(ds, db); dynstr_append_mem(ds, ",", 1); - port_end= int10_to_str(port, port_buff, 10); - replace_dynstr_append_mem(ds, port_buff, port_end - port_buff); + replace_dynstr_append_uint(ds, port); dynstr_append_mem(ds, ",", 1); if (sock) replace_dynstr_append(ds, sock); @@ -2619,148 +2941,150 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host, if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, CLIENT_MULTI_STATEMENTS)) { - handle_error("connect", q, mysql_errno(con), mysql_error(con), + handle_error(command, mysql_errno(con), mysql_error(con), mysql_sqlstate(con), ds); - *create_conn= 0; - goto err; + return 0; /* Not connected */ } - handle_no_error(q); - - /* - TODO: change this to 0 in future versions, but the 'kill' test relies on - existing behavior - */ - mysql_options(con, MYSQL_OPT_RECONNECT, (char *)&reconnect); - -err: - free_replace(); - free_replace_regex(); - return error; + handle_no_error(command); + return 1; /* Connected */ } /* Open a new connection to MySQL Server with the parameters - specified + specified. Make the new connection the current connection. SYNOPSIS - do_connect() - q called command + do_connect() + q called command DESCRIPTION - connect(<name>,<host>,<user>,<pass>,<db>,[<port>,<sock>[<opts>]]); - - <name> - name of the new connection - <host> - hostname of server - <user> - user to connect as - <pass> - password used when connecting - <db> - initial db when connected - <port> - server port - <sock> - server socket - <opts> - options to use for the connection - SSL - use SSL if available - COMPRESS - use compression if available - - */ - -int do_connect(struct st_query *q) -{ - char *con_name, *con_user,*con_pass, *con_host, *con_port_str, - *con_db, *con_sock, *con_options; - char *con_buf, *p; - char buff[FN_REFLEN]; - int con_port; - bool con_ssl= 0; - bool con_compress= 0; - int free_con_sock= 0; - int error= 0; - int create_conn= 1; - VAR *var_port, *var_sock; + connect(<name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]]); + connect <name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]]; + + <name> - name of the new connection + <host> - hostname of server + <user> - user to connect as + <pass> - password used when connecting + <db> - initial db when connected + <port> - server port + <sock> - server socket + <opts> - options to use for the connection + * SSL - use SSL if available + * COMPRESS - use compression if available + +*/ + +void do_connect(struct st_command *command) +{ + int con_port= port; + char *con_options; + bool con_ssl= 0, con_compress= 0; + char *ptr; + + DYNAMIC_STRING ds_connection_name; + DYNAMIC_STRING ds_host; + DYNAMIC_STRING ds_user; + DYNAMIC_STRING ds_password; + DYNAMIC_STRING ds_database; + DYNAMIC_STRING ds_port; + DYNAMIC_STRING ds_sock; + DYNAMIC_STRING ds_options; + const struct command_arg connect_args[] = { + "connection name", ARG_STRING, TRUE, &ds_connection_name, + "Name of the connection", + "host", ARG_STRING, TRUE, &ds_host, "Host to connect to", + "user", ARG_STRING, FALSE, &ds_user, "User to connect as", + "passsword", ARG_STRING, FALSE, &ds_password, + "Password used when connecting", + "database", ARG_STRING, FALSE, &ds_database, + "Dtabase 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" + }; DBUG_ENTER("do_connect"); - DBUG_PRINT("enter",("connect: %s", q->first_argument)); - - /* Make a copy of query before parsing, safe_get_param will modify */ - if (!(con_buf= my_strdup(q->first_argument, MYF(MY_WME)))) - die("Could not allocate con_buf"); - p= con_buf; - - if (*p != '(') - die("Syntax error in connect - expected '(' found '%c'", *p); - p++; - p= safe_get_param(p, &con_name, "Missing connection name"); - p= safe_get_param(p, &con_host, "Missing connection host"); - p= safe_get_param(p, &con_user, "Missing connection user"); - p= safe_get_param(p, &con_pass, "Missing connection password"); - p= safe_get_param(p, &con_db, "Missing connection db"); + DBUG_PRINT("enter",("connect: %s", command->first_argument)); - /* Port */ - p= safe_get_param(p, &con_port_str, 0); - if (*con_port_str) + /* Remove parenteses around connect arguments */ + if ((ptr= strstr(command->first_argument, "("))) { - if (*con_port_str == '$') + /* Replace it with a space */ + *ptr= ' '; + if ((ptr= strstr(command->first_argument, ")"))) { - if (!(var_port= var_get(con_port_str, 0, 0, 0))) - die("Unknown variable '%s'", con_port_str+1); - con_port= var_port->int_val; + /* Replace it with \0 */ + *ptr= 0; } else - { - con_port= atoi(con_port_str); - if (con_port == 0) - die("Illegal argument for port: '%s'", con_port_str); - } + die("connect - argument list started with '(' must be ended with ')'"); } - else + + check_command_args(command, command->first_argument, connect_args, + sizeof(connect_args)/sizeof(struct command_arg), + ','); + + /* Port */ + if (ds_port.length) { - con_port= port; + con_port= atoi(ds_port.str); + if (con_port == 0) + die("Illegal argument for port: '%s'", ds_port.str); } /* Sock */ - p= safe_get_param(p, &con_sock, 0); - if (*con_sock) + if (ds_sock.length) { - if (*con_sock == '$') + /* + If the socket is specified just as a name without path + append tmpdir in front + */ + if (*ds_sock.str != FN_LIBCHAR) { - if (!(var_sock= var_get(con_sock, 0, 0, 0))) - die("Unknown variable '%s'", con_sock+1); - if (!(con_sock= (char*)my_malloc(var_sock->str_val_len+1, MYF(0)))) - die("Out of memory"); - free_con_sock= 1; - memcpy(con_sock, var_sock->str_val, var_sock->str_val_len); - con_sock[var_sock->str_val_len]= 0; + char buff[FN_REFLEN]; + fn_format(buff, ds_sock.str, TMPDIR, "", 0); + dynstr_set(&ds_sock, buff); } } else { - con_sock= (char*) unix_sock; + /* No socket specified, use default */ + dynstr_set(&ds_sock, unix_sock); } + DBUG_PRINT("info", ("socket: %s", ds_sock.str)); + /* Options */ - p= safe_get_param(p, &con_options, 0); + con_options= ds_options.str; while (*con_options) { - char* str= con_options; - while (*str && !my_isspace(charset_info, *str)) - str++; - *str++= 0; - if (!strcmp(con_options, "SSL")) + char* end; + /* Step past any spaces in beginning of option*/ + while (*con_options && my_isspace(charset_info, *con_options)) + con_options++; + /* Find end of this option */ + end= con_options; + while (*end && !my_isspace(charset_info, *end)) + end++; + if (!strncmp(con_options, "SSL", 3)) con_ssl= 1; - else if (!strcmp(con_options, "COMPRESS")) + else if (!strncmp(con_options, "COMPRESS", 8)) con_compress= 1; else - die("Illegal option to connect: %s", con_options); - con_options= str; + die("Illegal option to connect: %.*s", end - con_options, con_options); + /* Process next option */ + con_options= end; } - /* Note: 'p' is pointing into the copy 'con_buf' */ - q->last_argument= q->first_argument + (p - con_buf); - if (next_con == cons_end) - die("Connection limit exhausted - increase MAX_CONS in mysqltest.c"); + if (next_con == connections_end) + die("Connection limit exhausted, you can have max %d connections", + (sizeof(connections)/sizeof(struct st_connection))); - if (find_connection_by_name(con_name)) - die("Connection %s already exists", con_name); + if (find_connection_by_name(ds_connection_name.str)) + die("Connection %s already exists", ds_connection_name.str); if (!mysql_init(&next_con->mysql)) die("Failed on mysql_init()"); @@ -2772,53 +3096,56 @@ int do_connect(struct st_query *q) #ifdef HAVE_OPENSSL if (opt_use_ssl || con_ssl) { - /* Turn on ssl_verify_server_cert only if host is "localhost" */ - opt_ssl_verify_server_cert= !strcmp(con_host, "localhost"); - mysql_ssl_set(&next_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); +#if MYSQL_VERSION_ID >= 50000 + /* Turn on ssl_verify_server_cert only if host is "localhost" */ + opt_ssl_verify_server_cert= !strcmp(ds_connection_name.str, "localhost"); mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &opt_ssl_verify_server_cert); +#endif } #endif - if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR) - con_sock=fn_format(buff, con_sock, TMPDIR, "", 0); - if (!con_db[0]) - con_db= db; + + /* Use default db name */ + if (ds_database.length == 0) + dynstr_set(&ds_database, db); + /* Special database to allow one to connect without a database name */ - if (con_db && !strcmp(con_db,"*NO-ONE*")) - con_db= 0; - if (q->abort_on_error) - { - if (safe_connect(&next_con->mysql, con_host, con_user, con_pass, - con_db, con_port, con_sock ? con_sock: 0)) - die("Could not open connection '%s': %d %s", con_name, - mysql_errno(&next_con->mysql), mysql_error(&next_con->mysql)); - } - else - error= connect_n_handle_errors(q, &next_con->mysql, con_host, con_user, - con_pass, con_db, con_port, con_sock, - &create_conn); + if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*")) + dynstr_set(&ds_database, ""); + - if (create_conn) + if (connect_n_handle_errors(command, &next_con->mysql, + ds_host.str,ds_user.str, + ds_password.str, ds_database.str, + con_port, ds_sock.str)) { - if (!(next_con->name= my_strdup(con_name, MYF(MY_WME)))) - die(NullS); + DBUG_PRINT("info", ("Inserting connection %s in connection pool", + ds_connection_name.str)); + if (!(next_con->name= my_strdup(ds_connection_name.str, MYF(MY_WME)))) + die("Out of memory"); cur_con= next_con++; } - if (free_con_sock) - my_free(con_sock, MYF(MY_WME)); - my_free(con_buf, MYF(MY_WME)); - DBUG_RETURN(error); + + dynstr_free(&ds_connection_name); + dynstr_free(&ds_host); + dynstr_free(&ds_user); + dynstr_free(&ds_password); + dynstr_free(&ds_database); + dynstr_free(&ds_port); + dynstr_free(&ds_sock); + dynstr_free(&ds_options); + DBUG_VOID_RETURN; } -int do_done(struct st_query *q) +int do_done(struct st_command *command) { /* Check if empty block stack */ if (cur_block == block_stack) { - if (*q->query != '}') + if (*command->query != '}') die("Stray 'end' command - end of block before beginning"); die("Stray '}' - end of block before beginning"); } @@ -2844,31 +3171,31 @@ int do_done(struct st_query *q) Process start of a "if" or "while" statement SYNOPSIS - do_block() - cmd Type of block - q called command + do_block() + cmd Type of block + q called command DESCRIPTION - if ([!]<expr>) - { - <block statements> - } + if ([!]<expr>) + { + <block statements> + } - while ([!]<expr>) - { - <block statements> - } + while ([!]<expr>) + { + <block statements> + } - Evaluates the <expr> and if it evaluates to - greater than zero executes the following code block. - A '!' can be used before the <expr> to indicate it should - be executed if it evaluates to zero. + Evaluates the <expr> and if it evaluates to + greater than zero executes the following code block. + A '!' can be used before the <expr> to indicate it should + be executed if it evaluates to zero. - */ +*/ -void do_block(enum block_cmd cmd, struct st_query* q) +void do_block(enum block_cmd cmd, struct st_command* command) { - char *p= q->first_argument; + char *p= command->first_argument; const char *expr_start, *expr_end; VAR v; const char *cmd_name= (cmd == cmd_while ? "while" : "if"); @@ -2912,9 +3239,7 @@ void do_block(enum block_cmd cmd, struct st_query* q) while (*p && my_isspace(charset_info, *p)) p++; - if (*p == '{') - die("Missing newline between %s and '{'", cmd_name); - if (*p) + if (*p && *p != '{') die("Missing '{' after %s. Found \"%s\"", cmd_name, p); var_init(&v,0,0,0,0); @@ -2935,43 +3260,41 @@ void do_block(enum block_cmd cmd, struct st_query* q) } -/* - Read characters from line buffer or file. This is needed to allow - my_ungetc() to buffer MAX_DELIMITER characters for a file +void do_delimiter(struct st_command* command) +{ + char* p= command->first_argument; + DBUG_ENTER("do_delimiter"); + DBUG_PRINT("enter", ("first_argument: %s", command->first_argument)); - NOTE: - This works as long as one doesn't change files (with 'source file_name') - when there is things pushed into the buffer. This should however not - happen for any tests in the test suite. -*/ + while (*p && my_isspace(charset_info, *p)) + p++; -int my_getc(FILE *file) -{ - if (line_buffer_pos == line_buffer) - return fgetc(file); - return *--line_buffer_pos; -} + if (!(*p)) + die("Can't set empty delimiter"); -void my_ungetc(int c) -{ - *line_buffer_pos++= (char) c; + strmake(delimiter, p, sizeof(delimiter) - 1); + delimiter_length= strlen(delimiter); + + DBUG_PRINT("exit", ("delimiter: %s", delimiter)); + command->last_argument= p + delimiter_length; + DBUG_VOID_RETURN; } -my_bool end_of_query(int c) +my_bool match_delimiter(int c, const char *delim, uint length) { uint i; - char tmp[MAX_DELIMITER]; + char tmp[MAX_DELIMITER_LENGTH]; - if (c != *delimiter) + if (c != *delim) return 0; - for (i= 1; i < delimiter_length && - (c= my_getc(cur_file->file)) == *(delimiter + i); + for (i= 1; i < length && + (c= my_getc(cur_file->file)) == *(delim + i); i++) tmp[i]= c; - if (i == delimiter_length) + if (i == length) return 1; /* Found delimiter */ /* didn't find delimiter, push back things that we read */ @@ -2982,45 +3305,51 @@ my_bool end_of_query(int c) } +my_bool end_of_query(int c) +{ + return match_delimiter(c, delimiter, delimiter_length); +} + + /* Read one "line" from the file SYNOPSIS - read_line - buf buffer for the read line - size size of the buffer i.e max size to read + read_line + buf buffer for the read line + size size of the buffer i.e max size to read DESCRIPTION - This function actually reads several lines and adds them to the - buffer buf. It continues to read until it finds what it believes - is a complete query. + This function actually reads several lines and adds them to the + buffer buf. It continues to read until it finds what it believes + is a complete query. - Normally that means it will read lines until it reaches the - "delimiter" that marks end of query. Default delimiter is ';' - The function should be smart enough not to detect delimiter's - found inside strings surrounded with '"' and '\'' escaped strings. + Normally that means it will read lines until it reaches the + "delimiter" that marks end of query. Default delimiter is ';' + The function should be smart enough not to detect delimiter's + found inside strings surrounded with '"' and '\'' escaped strings. - If the first line in a query starts with '#' or '-' this line is treated - as a comment. A comment is always terminated when end of line '\n' is - reached. + If the first line in a query starts with '#' or '-' this line is treated + as a comment. A comment is always terminated when end of line '\n' is + reached. */ int read_line(char *buf, int size) { - int c; - char quote; + char c, last_quote; char *p= buf, *buf_end= buf + size - 1; - int no_save= 0; - enum {R_NORMAL, R_Q, R_Q_IN_Q, R_SLASH_IN_Q, - R_COMMENT, R_LINE_START} state= R_LINE_START; + int skip_char= 0; + enum {R_NORMAL, R_Q, R_SLASH_IN_Q, + R_COMMENT, R_LINE_START} state= R_LINE_START; DBUG_ENTER("read_line"); - LINT_INIT(quote); + LINT_INIT(last_quote); start_lineno= cur_file->lineno; + DBUG_PRINT("info", ("start_lineno: %d", start_lineno)); for (; p < buf_end ;) { - no_save= 0; + skip_char= 0; c= my_getc(cur_file->file); if (feof(cur_file->file)) { @@ -3036,12 +3365,13 @@ int read_line(char *buf, int size) { /* We're back at the first file, check if all { have matching } - */ + */ if (cur_block != block_stack) die("Missing end of block"); + *p= 0; DBUG_PRINT("info", ("end of file")); - DBUG_RETURN(1); + DBUG_RETURN(1); } cur_file--; start_lineno= cur_file->lineno; @@ -3055,61 +3385,74 @@ int read_line(char *buf, int size) /* Convert cr/lf to lf */ if (p != buf && *(p-1) == '\r') - *(p-1)= 0; + p--; } switch(state) { case R_NORMAL: - /* Only accept '{' in the beginning of a line */ if (end_of_query(c)) { *p= 0; + DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter)); DBUG_RETURN(0); } - else if (c == '\'' || c == '"' || c == '`') + else if ((c == '{' && + (!strncasecmp(buf, "while", min(5, p - buf)) || + !strncasecmp(buf, "if", min(2, p - buf))))) { - quote= c; - state= R_Q; + /* Only if and while commands can be terminated by { */ + *p++= c; + *p= 0; + DBUG_PRINT("exit", ("Found '{' indicating begining of block")); + DBUG_RETURN(0); } - else if (c == '\n') + else if (c == '\'' || c == '"' || c == '`') { - state = R_LINE_START; + last_quote= c; + state= R_Q; } break; + case R_COMMENT: if (c == '\n') { + /* Comments are terminated by newline */ *p= 0; + DBUG_PRINT("exit", ("Found newline in comment")); DBUG_RETURN(0); } break; + case R_LINE_START: - /* Only accept start of comment if this is the first line in query */ - if ((cur_file->lineno == start_lineno) && - (c == '#' || c == '-' || parsing_disabled)) + if (c == '#' || c == '-') { + /* A # or - in the first position of the line - this is a comment */ state = R_COMMENT; } else if (my_isspace(charset_info, c)) { + /* Skip all space at begining of line */ if (c == '\n') start_lineno= cur_file->lineno; /* Query hasn't started yet */ - no_save= 1; + skip_char= 1; } - else if (c == '}') + else if (end_of_query(c)) { - *buf++= '}'; - *buf= 0; + *p= 0; + DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter)); DBUG_RETURN(0); } - else if (end_of_query(c) || c == '{') + else if (c == '}') { + /* A "}" need to be by itself in the begining of a line to terminate */ + *p++= c; *p= 0; + DBUG_PRINT("exit", ("Found '}' in begining of a line")); DBUG_RETURN(0); } else if (c == '\'' || c == '"' || c == '`') { - quote= c; + last_quote= c; state= R_Q; } else @@ -3117,29 +3460,19 @@ int read_line(char *buf, int size) break; case R_Q: - if (c == quote) - state= R_Q_IN_Q; + if (c == last_quote) + state= R_NORMAL; else if (c == '\\') state= R_SLASH_IN_Q; break; - case R_Q_IN_Q: - if (end_of_query(c)) - { - *p= 0; - DBUG_RETURN(0); - } - if (c != quote) - state= R_NORMAL; - else - state= R_Q; - break; + case R_SLASH_IN_Q: state= R_Q; break; } - if (!no_save) + if (!skip_char) { /* Could be a multibyte character */ /* This code is based on the code in "sql_load.cc" */ @@ -3157,7 +3490,7 @@ int read_line(char *buf, int size) for (i= 1; i < charlen; i++) { if (feof(cur_file->file)) - goto found_eof; /* FIXME: could we just break here?! */ + goto found_eof; c= my_getc(cur_file->file); *p++ = c; } @@ -3174,99 +3507,253 @@ int read_line(char *buf, int size) *p++= c; } } - *p= 0; /* Always end with \0 */ - DBUG_RETURN(feof(cur_file->file)); + die("The input buffer is too small for this query.x\n" \ + "check your query or increase MAX_QUERY and recompile"); + DBUG_RETURN(0); } + /* - Create a query from a set of lines + Convert the read query to result format version 1 + + That is: After newline, all spaces need to be skipped + unless the previous char was a quote + + This is due to an old bug that has now been fixed, but the + version 1 output format is preserved by using this function + +*/ + +void convert_to_format_v1(char* query) +{ + int last_c_was_quote= 0; + char *p= query, *write= query; + char *end= strend(query); + char last_c; + + while (p <= end) + { + if (*p == '\n' && !last_c_was_quote) + { + *write++ = *p++; /* Save the newline */ + + /* Skip any spaces on next line */ + while (*p && my_isspace(charset_info, *p)) + p++; + + last_c_was_quote= 0; + } + else if (*p == '\'' || *p == '"' || *p == '`') + { + last_c= *p; + *write++ = *p++; + + /* Copy anything until the next quote of same type */ + while (*p && *p != last_c) + *write++ = *p++; + + *write++ = *p++; + + last_c_was_quote= 1; + } + else + { + *write++ = *p++; + last_c_was_quote= 0; + } + } +} + + +/* + Check a command that is about to be sent (or should have been + sent if parsing was enabled) to mysql server for + suspicious things and generate warnings. +*/ + +void scan_command_for_warnings(struct st_command *command) +{ + const char *ptr= command->query; + DBUG_ENTER("scan_command_for_warnings"); + DBUG_PRINT("enter", ("query: %s", command->query)); + + while(*ptr) + { + /* + Look for query's that lines that start with a -- comment + and has a mysqltest command + */ + if (ptr[0] == '\n' && + ptr[1] && ptr[1] == '-' && + ptr[2] && ptr[2] == '-' && + ptr[3]) + { + uint type; + char save; + char *end, *start= (char*)ptr+3; + /* Skip leading spaces */ + while (*start && my_isspace(charset_info, *start)) + start++; + end= start; + /* Find end of command(next space) */ + while (*end && !my_isspace(charset_info, *end)) + end++; + save= *end; + *end= 0; + DBUG_PRINT("info", ("Checking '%s'", start)); + type= find_type(start, &command_typelib, 1+2); + if (type) + warning_msg("Embedded mysqltest command '--%s' detected in " + "query '%s' was this intentional? ", + start, command->query); + *end= save; + } + + ptr++; + } + DBUG_VOID_RETURN; +} + +/* + Check for unexpected "junk" after the end of query + This is normally caused by missing delimiters or when + switching between different delimiters +*/ + +void check_eol_junk_line(const char *line) +{ + const char *p= line; + DBUG_ENTER("check_eol_junk_line"); + DBUG_PRINT("enter", ("line: %s", line)); + + /* Check for extra delimiter */ + if (*p && !strncmp(p, delimiter, delimiter_length)) + die("Extra delimiter \"%s\" found", delimiter); + + /* Allow trailing # comment */ + if (*p && *p != '#') + { + if (*p == '\n') + die("Missing delimiter"); + die("End of line junk detected: \"%s\"", p); + } + DBUG_VOID_RETURN; +} + +void check_eol_junk(const char *eol) +{ + const char *p= eol; + DBUG_ENTER("check_eol_junk"); + DBUG_PRINT("enter", ("eol: %s", eol)); + + /* Skip past all spacing chars and comments */ + while (*p && (my_isspace(charset_info, *p) || *p == '#' || *p == '\n')) + { + /* Skip past comments started with # and ended with newline */ + if (*p && *p == '#') + { + p++; + while (*p && *p != '\n') + p++; + } + + /* Check this line */ + if (*p && *p == '\n') + check_eol_junk_line(p); + + if (*p) + p++; + } + + check_eol_junk_line(p); + + DBUG_VOID_RETURN; +} + + + +/* + Create a command from a set of lines SYNOPSIS - read_query() - q_ptr pointer where to return the new query + read_command() + command_ptr pointer where to return the new query DESCRIPTION - Converts lines returned by read_line into a query, this involves - parsing the first word in the read line to find the query type. + Converts lines returned by read_line into a command, this involves + parsing the first word in the read line to find the command type. - A -- comment may contain a valid query as the first word after the - comment start. Thus it's always checked to see if that is the case. - The advantage with this approach is to be able to execute commands - terminated by new line '\n' regardless how many "delimiter" it contain. + A -- comment may contain a valid query as the first word after the + comment start. Thus it's always checked to see if that is the case. + The advantage with this approach is to be able to execute commands + terminated by new line '\n' regardless how many "delimiter" it contain. */ -static char read_query_buf[MAX_QUERY]; +#define MAX_QUERY (256*1024) /* 256K -- a test in sp-big is >128K */ +static char read_command_buf[MAX_QUERY]; -int read_query(struct st_query** q_ptr) +int read_command(struct st_command** command_ptr) { - char *p= read_query_buf; - struct st_query* q; - DBUG_ENTER("read_query"); + char *p= read_command_buf; + struct st_command* command; + DBUG_ENTER("read_command"); if (parser.current_line < parser.read_lines) { - get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ; + get_dynamic(&q_lines, (gptr) command_ptr, parser.current_line) ; DBUG_RETURN(0); } - if (!(*q_ptr= q= (struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || - insert_dynamic(&q_lines, (gptr) &q)) + if (!(*command_ptr= command= + (struct st_command*) my_malloc(sizeof(*command), MYF(MY_WME))) || + insert_dynamic(&q_lines, (gptr) &command)) die(NullS); - q->record_file[0]= 0; - q->require_file= 0; - q->first_word_len= 0; + command->require_file[0]= 0; + command->first_word_len= 0; + command->query_len= 0; - q->type= Q_UNKNOWN; - q->query_buf= q->query= 0; - read_query_buf[0]= 0; - if (read_line(read_query_buf, sizeof(read_query_buf))) + command->type= Q_UNKNOWN; + command->query_buf= command->query= 0; + read_command_buf[0]= 0; + if (read_line(read_command_buf, sizeof(read_command_buf))) { - check_eol_junk(read_query_buf); + check_eol_junk(read_command_buf); DBUG_RETURN(1); } - - DBUG_PRINT("info", ("query: %s", read_query_buf)); - if (*p == '#') - { - q->type= Q_COMMENT; - /* This goto is to avoid losing the "expected error" info. */ - goto end; - } - if (!parsing_disabled) - { - memcpy((gptr) q->expected_errno, (gptr) global_expected_errno, - sizeof(global_expected_errno)); - q->expected_errors= global_expected_errors; - q->abort_on_error= (global_expected_errors == 0 && abort_on_error); - } - if (p[0] == '-' && p[1] == '-') + convert_to_format_v1(read_command_buf); + + DBUG_PRINT("info", ("query: %s", read_command_buf)); + if (*p == '#') { - q->type= Q_COMMENT_WITH_COMMAND; - p+= 2; /* To calculate first word */ + command->type= Q_COMMENT; } - else if (!parsing_disabled) + else if (p[0] == '-' && p[1] == '-') { - while (*p && my_isspace(charset_info, *p)) - p++ ; + command->type= Q_COMMENT_WITH_COMMAND; + p+= 2; /* Skip past -- */ } -end: + /* Skip leading spaces */ while (*p && my_isspace(charset_info, *p)) p++; - if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME)))) - die(NullS); + if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME)))) + die("Out of memory"); /* Calculate first word and first argument */ - for (p= q->query; *p && !my_isspace(charset_info, *p) ; p++) ; - q->first_word_len= (uint) (p - q->query); + for (p= command->query; *p && !my_isspace(charset_info, *p) ; p++) ; + command->first_word_len= (uint) (p - command->query); + + /* Skip spaces between command and first argument */ while (*p && my_isspace(charset_info, *p)) p++; - q->first_argument= p; - q->end= strend(q->query); + command->first_argument= p; + + command->end= strend(command->query); + command->query_len= (command->end - command->query); parser.read_lines++; DBUG_RETURN(0); } @@ -3278,8 +3765,6 @@ static struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test, - (gptr*) &opt_big_test, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use the compressed server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -3319,8 +3804,8 @@ static struct my_option my_long_options[] = {"record", 'r', "Record output of test_file into result file.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"result-file", 'R', "Read/Store result from/in this file.", - (gptr*) &result_file, (gptr*) &result_file, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, + (gptr*) &result_file_name, (gptr*) &result_file_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 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.", @@ -3348,8 +3833,6 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"user", 'u', "User for login.", (gptr*) &user, (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"valgrind", 'N', "Define VALGRIND_TEST to 1.", (gptr*) &opt_valgrind_test, - (gptr*) &opt_valgrind_test, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"verbose", 'v', "Write more.", (gptr*) &verbose, (gptr*) &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", @@ -3363,7 +3846,7 @@ static struct my_option my_long_options[] = #include <help_start.h> -static void print_version(void) +void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); @@ -3384,6 +3867,52 @@ void usage() #include <help_end.h> +/* + Read arguments for embedded server and put them into + embedded_server_args[] +*/ + +void read_embedded_server_arguments(const char *name) +{ + char argument[1024],buff[FN_REFLEN], *str=0; + FILE *file; + + if (!test_if_hard_path(name)) + { + strxmov(buff, opt_basedir, name, NullS); + name=buff; + } + fn_format(buff, name, "", "", MY_UNPACK_FILENAME); + + if (!embedded_server_arg_count) + { + embedded_server_arg_count=1; + embedded_server_args[0]= (char*) ""; /* Progname */ + } + if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) + die("Failed to open file %s", buff); + + while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS && + (str=fgets(argument,sizeof(argument), file))) + { + *(strend(str)-1)=0; /* Remove end newline */ + if (!(embedded_server_args[embedded_server_arg_count]= + (char*) my_strdup(str,MYF(MY_WME)))) + { + my_fclose(file,MYF(0)); + die("Out of memory"); + + } + embedded_server_arg_count++; + } + my_fclose(file,MYF(0)); + if (str) + die("Too many arguments in option file: %s",name); + + return; +} + + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -3398,35 +3927,35 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), record = 1; break; case 'x': + { + char buff[FN_REFLEN]; + if (!test_if_hard_path(argument)) { - char buff[FN_REFLEN]; - if (!test_if_hard_path(argument)) - { - strxmov(buff, opt_basedir, argument, NullS); - argument= buff; - } - fn_format(buff, argument, "", "", MY_UNPACK_FILENAME); - DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); - if (!(cur_file->file= - my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) - die("Could not open %s: errno = %d", buff, errno); - cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); - cur_file->lineno= 1; - break; + strxmov(buff, opt_basedir, argument, NullS); + argument= buff; } + fn_format(buff, argument, "", "", MY_UNPACK_FILENAME); + DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); + if (!(cur_file->file= + my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + die("Could not open %s: errno = %d", buff, errno); + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); + cur_file->lineno= 1; + break; + } case 'm': + { + static char buff[FN_REFLEN]; + if (!test_if_hard_path(argument)) { - static char buff[FN_REFLEN]; - if (!test_if_hard_path(argument)) - { - strxmov(buff, opt_basedir, argument, NullS); - argument= buff; - } - fn_format(buff, argument, "", "", MY_UNPACK_FILENAME); - timer_file= buff; - unlink(timer_file); /* Ignore error, may not exist */ - break; + strxmov(buff, opt_basedir, argument, NullS); + argument= buff; } + fn_format(buff, argument, "", "", MY_UNPACK_FILENAME); + timer_file= buff; + unlink(timer_file); /* Ignore error, may not exist */ + break; + } case 'p': if (argument) { @@ -3448,7 +3977,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), embedded_server_arg_count=1; embedded_server_args[0]= (char*) ""; } - if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 || !(embedded_server_args[embedded_server_arg_count++]= my_strdup(argument, MYF(MY_FAE)))) { @@ -3456,8 +3985,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } break; case 'F': - if (read_server_arguments(argument)) - die(NullS); + read_embedded_server_arguments(argument); break; case OPT_SKIP_SAFEMALLOC: #ifdef SAFEMALLOC @@ -3498,16 +4026,16 @@ int parse_args(int argc, char **argv) /* - Write the content of str into file + Write the content of str into file - SYNOPSIS - str_to_file - fname - name of file to truncate/create and write to - str - content to write to file - size - size of content witten to file + SYNOPSIS + str_to_file + fname - name of file to truncate/create and write to + str - content to write to file + size - size of content witten to file */ -static void str_to_file(const char *fname, char *str, int size) +void str_to_file(const char *fname, char *str, int size) { int fd; char buff[FN_REFLEN]; @@ -3519,7 +4047,7 @@ static void str_to_file(const char *fname, char *str, int size) fn_format(buff, fname, "", "", MY_UNPACK_FILENAME); if ((fd= my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, - MYF(MY_WME | MY_FFNF))) < 0) + MYF(MY_WME | MY_FFNF))) < 0) die("Could not open %s: errno = %d", buff, errno); if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP))) die("write failed"); @@ -3527,236 +4055,48 @@ static void str_to_file(const char *fname, char *str, int size) } -void dump_result_to_reject_file(const char *record_file, char *buf, int size) +void dump_result_to_reject_file(char *buf, int size) { char reject_file[FN_REFLEN]; - str_to_file(fn_format(reject_file, record_file, "", ".reject", + str_to_file(fn_format(reject_file, result_file_name, "", ".reject", MY_REPLACE_EXT), buf, size); } -void dump_result_to_log_file(const char *record_file, char *buf, int size) +void dump_result_to_log_file(char *buf, int size) { char log_file[FN_REFLEN]; - str_to_file(fn_format(log_file, record_file, "", ".log", + str_to_file(fn_format(log_file, result_file_name, "", ".log", MY_REPLACE_EXT), buf, size); } -void dump_progress(const char *record_file) +void dump_progress(void) { char log_file[FN_REFLEN]; - str_to_file(fn_format(log_file, record_file, "", ".progress", + str_to_file(fn_format(log_file, result_file_name, "", ".progress", MY_REPLACE_EXT), ds_progress.str, ds_progress.length); } -static void check_regerr(my_regex_t* r, int err) +void dump_warning_messages(void) { - char err_buf[1024]; + char warn_file[FN_REFLEN]; - if (err) - { - my_regerror(err,r,err_buf,sizeof(err_buf)); - die("Regex error: %s\n", err_buf); - } + str_to_file(fn_format(warn_file, result_file_name, "", ".warnings", + MY_REPLACE_EXT), + ds_warning_messages.str, ds_warning_messages.length); } -/* - auxiluary macro used by reg_replace - makes sure the result buffer has sufficient length -*/ -#define SECURE_REG_BUF if (buf_len < need_buf_len)\ - {\ - int off= res_p - buf;\ - buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE));\ - res_p= buf + off;\ - buf_len= need_buf_len;\ - }\ - -/* - Performs a regex substitution - - IN: - - buf_p - result buffer pointer. Will change if reallocated - buf_len_p - result buffer length. Will change if the buffer is reallocated - pattern - regexp pattern to match - replace - replacement expression - string - the string to perform substituions in - icase - flag, if set to 1 the match is case insensitive - */ -static int reg_replace(char** buf_p, int* buf_len_p, char *pattern, - char *replace, char *string, int icase) +void check_regerr(my_regex_t* r, int err) { - my_regex_t r; - my_regmatch_t* subs; - char* buf_end, *replace_end; - char* buf= *buf_p; - int len; - int buf_len,need_buf_len; - int cflags= REG_EXTENDED; - int err_code; - char* res_p,*str_p,*str_end; - - buf_len= *buf_len_p; - len= strlen(string); - str_end= string + len; - - /* start with a buffer of a reasonable size that hopefully will not - need to be reallocated - */ - need_buf_len= len * 2 + 1; - res_p= buf; + char err_buf[1024]; - SECURE_REG_BUF - - buf_end = buf + buf_len; - - if (icase) - cflags |= REG_ICASE; - - if ((err_code=my_regcomp(&r,pattern,cflags,&my_charset_latin1))) - { - check_regerr(&r,err_code); - return 1; - } - - subs= (my_regmatch_t*)my_malloc(sizeof(my_regmatch_t) * (r.re_nsub+1), - MYF(MY_WME+MY_FAE)); - - *res_p= 0; - str_p= string; - replace_end= replace + strlen(replace); - - /* for each pattern match instance perform a replacement */ - while (!err_code) + if (err) { - /* find the match */ - err_code= my_regexec(&r,str_p, r.re_nsub+1, subs, - (str_p == string) ? REG_NOTBOL : 0); - - /* if regular expression error (eg. bad syntax, or out of memory) */ - if (err_code && err_code != REG_NOMATCH) - { - check_regerr(&r,err_code); - my_regfree(&r); - return 1; - } - - /* if match found */ - if (!err_code) - { - char* expr_p= replace; - int c; - - /* - we need at least what we have so far in the buffer + the part - before this match - */ - need_buf_len= (res_p - buf) + subs[0].rm_so; - - /* on this pass, calculate the memory for the result buffer */ - while (expr_p < replace_end) - { - int back_ref_num= -1; - c= *expr_p; - - if (c == '\\' && expr_p + 1 < replace_end) - { - back_ref_num= expr_p[1] - '0'; - } - - /* found a valid back_ref (eg. \1)*/ - if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) - { - int start_off,end_off; - if ((start_off=subs[back_ref_num].rm_so) > -1 && - (end_off=subs[back_ref_num].rm_eo) > -1) - { - need_buf_len += (end_off - start_off); - } - expr_p += 2; - } - else - { - expr_p++; - need_buf_len++; - } - } - need_buf_len++; - /* - now that we know the size of the buffer, - make sure it is big enough - */ - SECURE_REG_BUF - - /* copy the pre-match part */ - if (subs[0].rm_so) - { - memcpy(res_p,str_p,subs[0].rm_so); - res_p += subs[0].rm_so; - } - - expr_p= replace; - - /* copy the match and expand back_refs */ - while (expr_p < replace_end) - { - int back_ref_num= -1; - c= *expr_p; - - if (c == '\\' && expr_p + 1 < replace_end) - { - back_ref_num= expr_p[1] - '0'; - } - - if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) - { - int start_off,end_off; - if ((start_off=subs[back_ref_num].rm_so) > -1 && - (end_off=subs[back_ref_num].rm_eo) > -1) - { - int block_len= end_off - start_off; - memcpy(res_p,str_p + start_off, block_len); - res_p += block_len; - } - expr_p += 2; - } - else - { - *res_p++ = *expr_p++; - } - } - - /* handle the post-match part */ - if (subs[0].rm_so == subs[0].rm_eo) - { - if (str_p + subs[0].rm_so >= str_end) - break; - str_p += subs[0].rm_eo ; - *res_p++ = *str_p++; - } - else - { - str_p += subs[0].rm_eo; - } - } - else /* no match this time, just copy the string as is */ - { - int left_in_str= str_end-str_p; - need_buf_len= (res_p-buf) + left_in_str; - SECURE_REG_BUF - memcpy(res_p,str_p,left_in_str); - res_p += left_in_str; - str_p= str_end; - } - } - my_regfree(&r); - *res_p= 0; - *buf_p= buf; - *buf_len_p= buf_len; - return 0; + my_regerror(err,r,err_buf,sizeof(err_buf)); + die("Regex error: %s\n", err_buf); + } } @@ -3768,12 +4108,12 @@ DYNAMIC_ARRAY patterns; init_win_path_patterns DESCRIPTION - Setup string patterns that will be used to detect filenames that - needs to be converted from Win to Unix format + Setup string patterns that will be used to detect filenames that + needs to be converted from Win to Unix format */ -static void init_win_path_patterns() +void init_win_path_patterns() { /* List of string patterns to match in order to find paths */ const char* paths[] = { "$MYSQL_TEST_DIR", @@ -3800,7 +4140,7 @@ static void init_win_path_patterns() p= my_strdup(paths[i], MYF(MY_FAE)); if (insert_dynamic(&patterns, (gptr) &p)) - die(NullS); + die(NullS); DBUG_PRINT("info", ("p: %s", p)); while (*p) @@ -3813,7 +4153,7 @@ static void init_win_path_patterns() DBUG_VOID_RETURN; } -static void free_win_path_patterns() +void free_win_path_patterns() { uint i= 0; for (i=0 ; i < patterns.elements ; i++) @@ -3828,17 +4168,17 @@ static void free_win_path_patterns() fix_win_paths DESCRIPTION - Search the string 'val' for the patterns that are known to be - strings that contain filenames. Convert all \ to / in the - filenames that are found. - - Ex: - val = 'Error "c:\mysql\mysql-test\var\test\t1.frm" didn't exist' - => $MYSQL_TEST_DIR is found by strstr - => all \ from c:\mysql\m... until next space is converted into / + Search the string 'val' for the patterns that are known to be + strings that contain filenames. Convert all \ to / in the + filenames that are found. + + Ex: + val = 'Error "c:\mysql\mysql-test\var\test\t1.frm" didn't exist' + => $MYSQL_TEST_DIR is found by strstr + => all \ from c:\mysql\m... until next space is converted into / */ -static void fix_win_paths(const char* val, int len) +void fix_win_paths(const char *val, int len) { uint i; char *p; @@ -3868,43 +4208,14 @@ static void fix_win_paths(const char* val, int len) } #endif -/* Append the string to ds, with optional replace */ -static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, - const char *val, int len) -{ -#ifdef __WIN__ - fix_win_paths(val, len); -#endif - - if (glob_replace_regex) - { - 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, ds, val, len); - else - dynstr_append_mem(ds, val, len); -} - - -/* Append zero-terminated string to ds, with optional replace */ -static void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val) -{ - replace_dynstr_append_mem(ds, val, strlen(val)); -} /* Append the result for one field to the dynamic string ds */ -static void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field, - const char* val, ulonglong len, bool is_null) +void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field, + const char* val, ulonglong len, bool is_null) { if (col_idx < max_replace_column && replace_column[col_idx]) { @@ -3955,7 +4266,7 @@ static void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field, Values may be converted with 'replace_column' */ -static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) +void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) { MYSQL_ROW row; uint num_fields= mysql_num_fields(res); @@ -3972,7 +4283,6 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1); } - free_replace_column(); } @@ -3981,8 +4291,8 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) with '\t'. Values may be converted with 'replace_column' */ -static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, - MYSQL_FIELD *fields, uint num_fields) +void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, + MYSQL_FIELD *fields, uint num_fields) { MYSQL_BIND *bind; my_bool *is_null; @@ -4028,8 +4338,6 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - free_replace_column(); - for (i= 0; i < num_fields; i++) { /* Free data for output */ @@ -4046,9 +4354,9 @@ static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, Append metadata for fields to output */ -static void append_metadata(DYNAMIC_STRING *ds, - MYSQL_FIELD *field, - uint num_fields) +void append_metadata(DYNAMIC_STRING *ds, + MYSQL_FIELD *field, + uint num_fields) { MYSQL_FIELD *field_end; dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t" @@ -4059,44 +4367,36 @@ static void append_metadata(DYNAMIC_STRING *ds, field < field_end ; field++) { - char buff[22]; dynstr_append_mem(ds, field->catalog, - field->catalog_length); + field->catalog_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->db, field->db_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->org_table, - field->org_table_length); + field->org_table_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->table, - field->table_length); + field->table_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->org_name, - field->org_name_length); + field->org_name_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->name, field->name_length); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->type, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->type); dynstr_append_mem(ds, "\t", 1); - longlong10_to_str((unsigned int) field->length, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->length); dynstr_append_mem(ds, "\t", 1); - longlong10_to_str((unsigned int) field->max_length, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->max_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? "N" : "Y"), 1); dynstr_append_mem(ds, "\t", 1); - - int10_to_str((int) field->flags, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->flags); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->decimals, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->decimals); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->charsetnr, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->charsetnr); dynstr_append_mem(ds, "\n", 1); } } @@ -4106,8 +4406,8 @@ static void append_metadata(DYNAMIC_STRING *ds, Append affected row count and other info to output */ -static void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows, - const char *info) +void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows, + const char *info) { char buf[40], buff2[21]; sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2)); @@ -4122,12 +4422,12 @@ static void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows, /* - Display the table headings with the names tab separated + Display the table headings with the names tab separated */ -static void append_table_headings(DYNAMIC_STRING *ds, - MYSQL_FIELD *field, - uint num_fields) +void append_table_headings(DYNAMIC_STRING *ds, + MYSQL_FIELD *field, + uint num_fields) { uint col_idx; for (col_idx= 0; col_idx < num_fields; col_idx++) @@ -4143,10 +4443,10 @@ static void append_table_headings(DYNAMIC_STRING *ds, Fetch warnings from server and append to ds RETURN VALUE - Number of warnings appended to ds + Number of warnings appended to ds */ -static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) +int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) { uint count; MYSQL_RES *warn_res; @@ -4195,9 +4495,9 @@ static int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) error - function will not return */ -static void run_query_normal(MYSQL *mysql, struct st_query *command, - int flags, char *query, int query_len, - DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) +void run_query_normal(MYSQL *mysql, struct st_command *command, + int flags, char *query, int query_len, + DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) { MYSQL_RES *res= 0; int err= 0, counter= 0; @@ -4205,20 +4505,20 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, DBUG_PRINT("enter",("flags: %d", flags)); DBUG_PRINT("enter", ("query: '%-.60s'", query)); - if (flags & QUERY_SEND) + if (flags & QUERY_SEND_FLAG) { /* - Send the query - */ + Send the query + */ if (mysql_send_query(mysql, query, query_len)) { - handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; } } - if (!(flags & QUERY_REAP)) + if (!(flags & QUERY_REAP_FLAG)) DBUG_VOID_RETURN; do @@ -4226,22 +4526,22 @@ static void run_query_normal(MYSQL *mysql, struct st_query *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)) { - handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; } /* - Store the result. If res is NULL, use mysql_field_count to - determine if that was expected - */ + Store the result. If res is NULL, use mysql_field_count to + determine if that was expected + */ if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql)) { - handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; } @@ -4297,7 +4597,7 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, if (err > 0) { /* We got an error from mysql_next_result, maybe expected */ - handle_error(query, command, mysql_errno(mysql), mysql_error(mysql), + handle_error(command, mysql_errno(mysql), mysql_error(mysql), mysql_sqlstate(mysql), ds); goto end; } @@ -4307,8 +4607,6 @@ static void run_query_normal(MYSQL *mysql, struct st_query *command, handle_no_error(command); end: - free_replace(); - free_replace_regex(); /* We save the return code (mysql_errno(mysql)) from the last call sent @@ -4324,58 +4622,62 @@ end: Handle errors which occurred during execution SYNOPSIS - handle_error() - query - query string - q - query context - err_errno - error number - err_error - error message - err_sqlstate - sql state - ds - dynamic string which is used for output buffer + handle_error() + q - query context + err_errno - error number + err_error - error message + err_sqlstate - sql state + ds - dynamic string which is used for output buffer NOTE - If there is an unexpected error this function will abort mysqltest - immediately. + If there is an unexpected error this function will abort mysqltest + immediately. RETURN VALUE - error - function will not return + error - function will not return */ -static void handle_error(const char *query, struct st_query *q, - unsigned int err_errno, const char *err_error, - const char *err_sqlstate, DYNAMIC_STRING *ds) +void handle_error(struct st_command *command, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds) { uint i; DBUG_ENTER("handle_error"); - if (q->require_file) + if (command->require_file[0]) { /* The query after a "--require" failed. This is fine as long the server returned a valid reponse. Don't allow 2013 or 2006 to trigger an abort_not_supported_test - */ + */ if (err_errno == CR_SERVER_LOST || err_errno == CR_SERVER_GONE_ERROR) - die("require query '%s' failed: %d: %s", query, err_errno, err_error); + die("require query '%s' failed: %d: %s", command->query, + err_errno, err_error); /* Abort the run of this test, pass the failed query as reason */ - abort_not_supported_test("Query '%s' failed, required functionality not supported", query); + abort_not_supported_test("Query '%s' failed, required functionality" \ + "not supported", command->query); } - if (q->abort_on_error) - die("query '%s' failed: %d: %s", query, err_errno, err_error); + if (command->abort_on_error) + die("query '%s' failed: %d: %s", command->query, err_errno, err_error); - for (i= 0 ; (uint) i < q->expected_errors ; i++) + DBUG_PRINT("info", ("expected_errors.count: %d", + command->expected_errors.count)); + for (i= 0 ; (uint) i < command->expected_errors.count ; i++) { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == err_errno)) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, err_sqlstate) == 0))) + if (((command->expected_errors.err[i].type == ERR_ERRNO) && + (command->expected_errors.err[i].code.errnum == err_errno)) || + ((command->expected_errors.err[i].type == ERR_SQLSTATE) && + (strncmp(command->expected_errors.err[i].code.sqlstate, + err_sqlstate, SQLSTATE_LENGTH) == 0))) { if (!disable_result_log) { - if (q->expected_errors == 1) + if (command->expected_errors.count == 1) { /* Only log error if there is one possible error */ dynstr_append_mem(ds, "ERROR ", 6); @@ -4385,9 +4687,9 @@ static void handle_error(const char *query, struct st_query *q, dynstr_append_mem(ds,"\n",1); } /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) + else if (command->expected_errors.err[0].type == ERR_SQLSTATE || + (command->expected_errors.err[0].type == ERR_ERRNO && + command->expected_errors.err[0].code.errnum != 0)) dynstr_append(ds,"Got one of the listed errors\n"); } /* OK */ @@ -4395,7 +4697,8 @@ static void handle_error(const char *query, struct st_query *q, } } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, q->expected_errors)); + DBUG_PRINT("info",("i: %d expected_errors: %d", i, + command->expected_errors.count)); if (!disable_result_log) { @@ -4408,13 +4711,14 @@ static void handle_error(const char *query, struct st_query *q, if (i) { - if (q->expected_errno[0].type == ERR_ERRNO) + if (command->expected_errors.err[0].type == ERR_ERRNO) die("query '%s' failed with wrong errno %d: '%s', instead of %d...", - q->query, err_errno, err_error, q->expected_errno[0].code.errnum); + 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...", - q->query, err_sqlstate, err_error, - q->expected_errno[0].code.sqlstate); + command->query, err_sqlstate, err_error, + command->expected_errors.err[0].code.sqlstate); } DBUG_VOID_RETURN; @@ -4425,30 +4729,30 @@ static void handle_error(const char *query, struct st_query *q, Handle absence of errors after execution SYNOPSIS - handle_no_error() - q - context of query + handle_no_error() + q - context of query RETURN VALUE - error - function will not return + error - function will not return */ -static void handle_no_error(struct st_query *q) +void handle_no_error(struct st_command *command) { DBUG_ENTER("handle_no_error"); - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + 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("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); + command->query, command->expected_errors.err[0].code.errnum); } - else if (q->expected_errno[0].type == ERR_SQLSTATE && - strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + 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...", - q->query, q->expected_errno[0].code.sqlstate); + command->query, command->expected_errors.err[0].code.sqlstate); } DBUG_VOID_RETURN; @@ -4470,9 +4774,9 @@ static void handle_no_error(struct st_query *q) error - function will not return */ -static void run_query_stmt(MYSQL *mysql, struct st_query *command, - char *query, int query_len, DYNAMIC_STRING *ds, - DYNAMIC_STRING *ds_warnings) +void run_query_stmt(MYSQL *mysql, struct st_command *command, + char *query, int query_len, DYNAMIC_STRING *ds, + DYNAMIC_STRING *ds_warnings) { MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ MYSQL_STMT *stmt; @@ -4503,7 +4807,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, */ if (mysql_stmt_prepare(stmt, query, query_len)) { - handle_error(query, command, mysql_stmt_errno(stmt), + handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); goto end; } @@ -4520,6 +4824,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, parameter markers. */ +#if MYSQL_VERSION_ID >= 50000 if (cursor_protocol_enabled) { /* @@ -4530,13 +4835,14 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } +#endif /* Execute the query */ if (mysql_stmt_execute(stmt)) { - handle_error(query, command, mysql_stmt_errno(stmt), + handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); goto end; } @@ -4550,8 +4856,8 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, /* We instruct that we want to update the "max_length" field in - mysql_stmt_store_result(), this is our only way to know how much - buffer to allocate for result data + mysql_stmt_store_result(), this is our only way to know how much + buffer to allocate for result data */ { my_bool one= 1; @@ -4566,7 +4872,7 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, */ if (mysql_stmt_store_result(stmt)) { - handle_error(query, command, mysql_stmt_errno(stmt), + handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); goto end; } @@ -4636,9 +4942,6 @@ static void run_query_stmt(MYSQL *mysql, struct st_query *command, } end: - free_replace(); - free_replace_regex(); - if (!disable_warnings) { dynstr_free(&ds_prepare_warnings); @@ -4650,7 +4953,7 @@ end: to the server into the mysqltest builtin variable $mysql_errno. This variable then can be used from the test case itself. */ - + var_set_errno(mysql_stmt_errno(stmt)); #ifndef BUG15518_FIXED mysql_stmt_close(stmt); @@ -4668,7 +4971,7 @@ end: as view, sp etc. */ -static int util_query(MYSQL* org_mysql, const char* query){ +int util_query(MYSQL* org_mysql, const char* query){ MYSQL* mysql; DBUG_ENTER("util_query"); @@ -4679,11 +4982,9 @@ static int util_query(MYSQL* org_mysql, const char* query){ if (!(mysql= mysql_init(mysql))) die("Failed in mysql_init()"); - if (safe_connect(mysql, org_mysql->host, org_mysql->user, - org_mysql->passwd, org_mysql->db, org_mysql->port, - org_mysql->unix_socket)) - die("Could not open util connection: %d %s", - mysql_errno(mysql), mysql_error(mysql)); + safe_connect(mysql, "util", org_mysql->host, org_mysql->user, + org_mysql->passwd, org_mysql->db, org_mysql->port, + org_mysql->unix_socket); cur_con->util_mysql= mysql; } @@ -4697,8 +4998,8 @@ static int util_query(MYSQL* org_mysql, const char* query){ Run query flags control the phased/stages of query execution to be performed - if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on - the result will be read - for regular query, both bits must be on + if QUERY_SEND_FLAG bit is on, the query will be sent. If QUERY_REAP_FLAG + is on the result will be read - for regular query, both bits must be on SYNPOSIS run_query @@ -4707,7 +5008,7 @@ static int util_query(MYSQL* org_mysql, const char* query){ */ -static void run_query(MYSQL *mysql, struct st_query *command, int flags) +void run_query(MYSQL *mysql, struct st_command *command, int flags) { DYNAMIC_STRING *ds; DYNAMIC_STRING ds_result; @@ -4716,17 +5017,21 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) char *query; int query_len; my_bool view_created= 0, sp_created= 0; - my_bool complete_query= ((flags & QUERY_SEND) && (flags & QUERY_REAP)); + my_bool complete_query= ((flags & QUERY_SEND_FLAG) && + (flags & QUERY_REAP_FLAG)); init_dynamic_string(&ds_warnings, NULL, 0, 256); + /* Scan for warning before sendign to server */ + scan_command_for_warnings(command); + /* Evaluate query if this is an eval command - */ + */ if (command->type == Q_EVAL) { - init_dynamic_string(&eval_query, "", 16384, 65536); - do_eval(&eval_query, command->query, FALSE); + init_dynamic_string(&eval_query, "", command->query_len+256, 1024); + do_eval(&eval_query, command->query, command->end, FALSE); query = eval_query.str; query_len = eval_query.length; } @@ -4737,23 +5042,23 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) } /* - When command->record_file is set the output of _this_ query + When command->require_file is set the output of _this_ query should be compared with an already existing file Create a temporary dynamic string to contain the output from this query. - */ - if (command->record_file[0]) + */ + if (command->require_file[0]) { - init_dynamic_string(&ds_result, "", 16384, 65536); + init_dynamic_string(&ds_result, "", 1024, 1024); ds= &ds_result; } else ds= &ds_res; /* - Log the query into the output buffer + Log the query into the output buffer */ - if (!disable_query_log && (flags & QUERY_SEND)) + if (!disable_query_log && (flags & QUERY_SEND_FLAG)) { replace_dynstr_append_mem(ds, query, query_len); dynstr_append_mem(ds, delimiter, delimiter_length); @@ -4765,8 +5070,8 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) match_re(&view_re, query)) { /* - Create the query as a view. - Use replace since view can exist from a failed mysqltest run + Create the query as a view. + Use replace since view can exist from a failed mysqltest run */ DYNAMIC_STRING query_str; init_dynamic_string(&query_str, @@ -4778,7 +5083,7 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) /* Failed to create the view, this is not fatal just run the query the normal way - */ + */ DBUG_PRINT("view_create_error", ("Failed to create view '%s': %d: %s", query_str.str, mysql_errno(mysql), mysql_error(mysql))); @@ -4791,14 +5096,14 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) { /* Yes, it was possible to create this query as a view - */ + */ view_created= 1; query= (char*)"SELECT * FROM mysqltest_tmp_v"; query_len = strlen(query); /* - Collect warnings from create of the view that should otherwise - have been produced when the SELECT was executed + Collect warnings from create of the view that should otherwise + have been produced when the SELECT was executed */ append_warnings(&ds_warnings, cur_con->util_mysql); } @@ -4877,26 +5182,14 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) mysql_errno(mysql), mysql_error(mysql)); } - if (command->record_file[0]) + if (command->require_file[0]) { - /* A result file was specified for _this_ query */ - if (record) - { - /* - Recording in progress - Dump the output from _this_ query to the specified record_file - */ - str_to_file(command->record_file, ds->str, ds->length); - - } else { - - /* - The output from _this_ query should be checked against an already - existing file which has been specified using --require or --result - */ - check_result(ds, command->record_file, command->require_file); - } + /* A result file was specified for _this_ query + and the output should be checked against an already + existing file which has been specified using --require or --result + */ + check_require(ds, command->require_file); } dynstr_free(&ds_warnings); @@ -4906,12 +5199,12 @@ static void run_query(MYSQL *mysql, struct st_query *command, int flags) dynstr_free(&eval_query); } +/****************************************************************************/ +/* + Functions to detect different SQL statements +*/ -/****************************************************************************\ - * Functions to detect different SQL statements -\****************************************************************************/ - -static char *re_eprint(int err) +char *re_eprint(int err) { static char epbuf[100]; size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, @@ -4920,7 +5213,7 @@ static char *re_eprint(int err) return(epbuf); } -static void init_re_comp(my_regex_t *re, const char* str) +void init_re_comp(my_regex_t *re, const char* str) { int err= my_regcomp(re, str, (REG_EXTENDED | REG_ICASE | REG_NOSUB), &my_charset_latin1); @@ -4933,11 +5226,11 @@ static void init_re_comp(my_regex_t *re, const char* str) } } -static void init_re(void) +void init_re(void) { /* - Filter for queries that can be run using the - MySQL Prepared Statements C API + Filter for queries that can be run using the + MySQL Prepared Statements C API */ const char *ps_re_str = "^(" @@ -4954,13 +5247,13 @@ static void init_re(void) "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; /* - Filter for queries that can be run using the - Stored procedures + Filter for queries that can be run using the + Stored procedures */ const char *sp_re_str =ps_re_str; /* - Filter for queries that can be run as views + Filter for queries that can be run as views */ const char *view_re_str = "^(" @@ -4972,7 +5265,7 @@ static void init_re(void) } -static int match_re(my_regex_t *re, char *str) +int match_re(my_regex_t *re, char *str) { int err= my_regexec(re, str, (size_t)0, NULL, 0); @@ -4990,7 +5283,7 @@ static int match_re(my_regex_t *re, char *str) return 0; } -static void free_re(void) +void free_re(void) { my_regfree(&ps_re); my_regfree(&sp_re); @@ -5000,142 +5293,85 @@ static void free_re(void) /****************************************************************************/ -void get_query_type(struct st_query* q) +void get_command_type(struct st_command* command) { char save; uint type; - DBUG_ENTER("get_query_type"); + DBUG_ENTER("get_command_type"); - if (!parsing_disabled && *q->query == '}') + if (*command->query == '}') { - q->type = Q_END_BLOCK; + command->type = Q_END_BLOCK; DBUG_VOID_RETURN; } - if (q->type != Q_COMMENT_WITH_COMMAND) - q->type= parsing_disabled ? Q_COMMENT : Q_QUERY; - save=q->query[q->first_word_len]; - q->query[q->first_word_len]=0; - type=find_type(q->query, &command_typelib, 1+2); - q->query[q->first_word_len]=save; + save= command->query[command->first_word_len]; + command->query[command->first_word_len]= 0; + type= find_type(command->query, &command_typelib, 1+2); + command->query[command->first_word_len]= save; if (type > 0) { - q->type=(enum enum_commands) type; /* Found command */ + command->type=(enum enum_commands) type; /* Found command */ + /* - If queries are disabled, only recognize - --enable_parsing and --disable_parsing + Look for case where "query" was explicitly specified to + force command being sent to server */ - if (parsing_disabled && q->type != Q_ENABLE_PARSING && - q->type != Q_DISABLE_PARSING) - q->type= Q_COMMENT; + if (type == Q_QUERY) + { + /* Skip the "query" part */ + command->query= command->first_argument; + } } - else if (q->type == Q_COMMENT_WITH_COMMAND && - q->first_word_len && - q->query[q->first_word_len-1] == ';') + else { - /* - Detect comment with command using extra delimiter - Ex --disable_query_log; - ^ Extra delimiter causing the command - to be skipped - */ - save= q->query[q->first_word_len-1]; - q->query[q->first_word_len-1]= 0; - type= find_type(q->query, &command_typelib, 1+2); - q->query[q->first_word_len-1]= save; - if (type > 0) - die("Extra delimiter \";\" found"); - } - DBUG_VOID_RETURN; -} - - -static byte *get_var_key(const byte* var, uint* len, - my_bool __attribute__((unused)) t) -{ - register char* key; - key = ((VAR*)var)->name; - *len = ((VAR*)var)->name_len; - return (byte*)key; -} + /* No mysqltest command matched */ -static VAR *var_init(VAR *v, const char *name, int name_len, const char *val, - int val_len) -{ - int val_alloc_len; - VAR *tmp_var; - if (!name_len && name) - name_len = strlen(name); - if (!val_len && val) - val_len = strlen(val) ; - val_alloc_len = val_len + 16; /* room to grow */ - if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var) - + name_len+1, MYF(MY_WME)))) - die("Out of memory"); - - tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0; - tmp_var->alloced = (v == 0); - - if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME)))) - die("Out of memory"); + if (command->type != Q_COMMENT_WITH_COMMAND) + { + /* A query that will sent to mysqld */ + command->type= Q_QUERY; + } + else + { + /* -- comment that didn't contain a mysqltest command */ + command->type= Q_COMMENT; + warning_msg("Suspicious command '--%s' detected, was this intentional? "\ + "Use # instead of -- to avoid this warning", + command->query); + + if (command->first_word_len && + strcmp(command->query + command->first_word_len - 1, delimiter) == 0) + { + /* + Detect comment with command using extra delimiter + Ex --disable_query_log; + ^ Extra delimiter causing the command + to be skipped + */ + save= command->query[command->first_word_len-1]; + command->query[command->first_word_len-1]= 0; + if (find_type(command->query, &command_typelib, 1+2) > 0) + die("Extra delimiter \";\" found"); + command->query[command->first_word_len-1]= save; - memcpy(tmp_var->name, name, name_len); - if (val) - { - memcpy(tmp_var->str_val, val, val_len); - tmp_var->str_val[val_len]= 0; + } + } } - 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; - tmp_var->env_s = 0; - return tmp_var; -} - -static void var_free(void *v) -{ - my_free(((VAR*) v)->str_val, MYF(MY_WME)); - if (((VAR*)v)->alloced) - my_free((char*) v, MYF(MY_WME)); -} - - -static VAR* var_from_env(const char *name, const char *def_val) -{ - const char *tmp; - VAR *v; - if (!(tmp = getenv(name))) - tmp = def_val; - - v = var_init(0, name, strlen(name), tmp, strlen(tmp)); - my_hash_insert(&var_hash, (byte*)v); - return v; -} + /* Set expected error on command */ + memcpy(&command->expected_errors, &saved_expected_errors, + sizeof(saved_expected_errors)); + DBUG_PRINT("info", ("There are %d expected errors", + command->expected_errors.count)); + command->abort_on_error= (command->expected_errors.count == 0 && + abort_on_error); -static void init_var_hash(MYSQL *mysql) -{ - VAR *v; - DBUG_ENTER("init_var_hash"); - if (hash_init(&var_hash, charset_info, - 1024, 0, 0, get_var_key, var_free, MYF(0))) - die("Variable hash initialization failed"); - my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0, - (opt_big_test) ? "1" : "0", 0)); - my_hash_insert(&var_hash, (byte*) var_init(0,"VALGRIND_TEST", 0, - (opt_valgrind_test) ? "1" : "0", - 0)); - v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0); - my_hash_insert(&var_hash, (byte*) v); - v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0); - my_hash_insert(&var_hash, (byte*) v); v= var_init(0,"DB", 2, db, 0); - my_hash_insert(&var_hash, (byte*) v); DBUG_VOID_RETURN; } + /* Record how many milliseconds it took to execute the test file up until the current line and save it in the dynamic string ds_progress. @@ -5144,7 +5380,9 @@ static void init_var_hash(MYSQL *mysql) test run completes */ -static void mark_progress(struct st_query* q __attribute__((unused)), int line) + +void mark_progress(struct st_command* command __attribute__((unused)), + int line) { char buf[32], *end; ulonglong timer= timer_now(); @@ -5178,47 +5416,63 @@ static void mark_progress(struct st_query* q __attribute__((unused)), int line) int main(int argc, char **argv) { - struct st_query *q; - my_bool require_file=0, q_send_flag=0, - query_executed= 0; + struct st_command *command; + my_bool q_send_flag= 0; + uint command_executed= 0, last_command_executed= 0; char save_file[FN_REFLEN]; MY_STAT res_info; MY_INIT(argv[0]); - /* Use all time until exit if no explicit 'start_timer' */ - timer_start= timer_now(); + save_file[0]= 0; + TMPDIR[0]= 0; - save_file[0]=0; - TMPDIR[0]=0; + /* Init expected errors */ + memset(&saved_expected_errors, 0, sizeof(saved_expected_errors)); - /* Init cons */ - memset(cons, 0, sizeof(cons)); - cons_end = cons + MAX_CONS; - next_con = cons + 1; - cur_con = cons; + /* Init connections */ + memset(connections, 0, sizeof(connections)); + connections_end= connections + + (sizeof(connections)/sizeof(struct st_connection)) - 1; + next_con= connections + 1; + cur_con= connections; /* Init file stack */ memset(file_stack, 0, sizeof(file_stack)); - file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1; + file_stack_end= + file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1; cur_file= file_stack; /* Init block stack */ memset(block_stack, 0, sizeof(block_stack)); - block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1; + block_stack_end= + block_stack + (sizeof(block_stack)/sizeof(struct st_block)) - 1; cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ cur_block->cmd= cmd_none; - my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, - INIT_Q_LINES); + my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024); + + if (hash_init(&var_hash, charset_info, + 1024, 0, 0, get_var_key, var_free, MYF(0))) + die("Variable hash initialization failed"); memset(&master_pos, 0, sizeof(master_pos)); - init_dynamic_string(&ds_res, "", 0, 65536); + parser.current_line= parser.read_lines= 0; + memset(&var_reg, 0, sizeof(var_reg)); + +#ifdef __WIN__ + init_tmp_sh_file(); + init_win_path_patterns(); +#endif + + init_dynamic_string(&ds_res, "", 65536, 65536); init_dynamic_string(&ds_progress, "", 0, 2048); + init_dynamic_string(&ds_warning_messages, "", 0, 2048); parse_args(argc, argv); - DBUG_PRINT("info",("result_file: '%s'", result_file ? result_file : "")); + DBUG_PRINT("info",("result_file: '%s'", + result_file_name ? result_file_name : "")); if (mysql_server_init(embedded_server_arg_count, embedded_server_args, (char**) embedded_server_groups)) @@ -5246,29 +5500,30 @@ int main(int argc, char **argv) mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); #ifdef HAVE_OPENSSL + +#if MYSQL_VERSION_ID >= 50000 opt_ssl_verify_server_cert= TRUE; /* Always on in mysqltest */ +#endif + if (opt_use_ssl) { mysql_ssl_set(&cur_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); +#if MYSQL_VERSION_ID >= 50000 mysql_options(&cur_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &opt_ssl_verify_server_cert); +#endif } #endif if (!(cur_con->name = my_strdup("default", MYF(MY_WME)))) die("Out of memory"); - if (safe_connect(&cur_con->mysql, host, user, pass, db, port, unix_sock)) - die("Could not open connection '%s': %d %s", cur_con->name, - mysql_errno(&cur_con->mysql), mysql_error(&cur_con->mysql)); - - init_var_hash(&cur_con->mysql); + safe_connect(&cur_con->mysql, cur_con->name, host, user, pass, + db, port, unix_sock); -#ifdef __WIN__ - init_tmp_sh_file(); - init_win_path_patterns(); -#endif + /* Use all time until exit if no explicit 'start_timer' */ + timer_start= timer_now(); /* Initialize $mysql_errno with -1, so we can @@ -5282,26 +5537,35 @@ int main(int argc, char **argv) open_file(opt_include); } - while (!read_query(&q)) + while (!read_command(&command)) { int current_line_inc = 1, processed = 0; - if (q->type == Q_UNKNOWN || q->type == Q_COMMENT_WITH_COMMAND) - get_query_type(q); + if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND) + get_command_type(command); + + if (parsing_disabled && + command->type != Q_ENABLE_PARSING && + command->type != Q_DISABLE_PARSING) + { + command->type= Q_COMMENT; + scan_command_for_warnings(command); + } + if (cur_block->ok) { - q->last_argument= q->first_argument; + command->last_argument= command->first_argument; processed = 1; - switch (q->type) { + switch (command->type) { case Q_CONNECT: - do_connect(q); + do_connect(command); break; - case Q_CONNECTION: select_connection(q); break; + case Q_CONNECTION: select_connection(command); break; case Q_DISCONNECT: case Q_DIRTY_CLOSE: - close_connection(q); break; - case Q_RPL_PROBE: do_rpl_probe(q); break; - case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; - case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; + 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_QUERY_LOG: disable_query_log=0; break; case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break; @@ -5316,18 +5580,21 @@ int main(int argc, char **argv) case Q_DISABLE_INFO: disable_info=1; break; case Q_ENABLE_METADATA: display_metadata=1; break; case Q_DISABLE_METADATA: display_metadata=0; break; - case Q_SOURCE: do_source(q); break; - case Q_SLEEP: do_sleep(q, 0); break; - case Q_REAL_SLEEP: do_sleep(q, 1); break; - case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(q); break; - case Q_INC: do_modify_var(q, DO_INC); break; - case Q_DEC: do_modify_var(q, DO_DEC); break; - case Q_ECHO: do_echo(q); query_executed= 1; break; - case Q_SYSTEM: do_system(q); break; + case Q_SOURCE: do_source(command); break; + case Q_SLEEP: do_sleep(command, 0); break; + case Q_REAL_SLEEP: do_sleep(command, 1); break; + case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(command); break; + case Q_INC: do_modify_var(command, DO_INC); break; + case Q_DEC: do_modify_var(command, DO_DEC); break; + case Q_ECHO: do_echo(command); command_executed++; break; + case Q_SYSTEM: do_system(command); break; + case Q_REMOVE_FILE: do_remove_file(command); break; + case Q_FILE_EXIST: do_file_exist(command); break; + case Q_WRITE_FILE: do_write_file(command); break; + case Q_COPY_FILE: do_copy_file(command); break; + case Q_PERL: do_perl(command); break; case Q_DELIMITER: - strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); - delimiter_length= strlen(delimiter); - q->last_argument= q->first_argument+delimiter_length; + do_delimiter(command); break; case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; @@ -5335,133 +5602,128 @@ int main(int argc, char **argv) case Q_DISPLAY_HORIZONTAL_RESULTS: display_result_vertically= FALSE; break; - case Q_LET: do_let(q); break; + case Q_LET: do_let(command); break; case Q_EVAL_RESULT: eval_result = 1; break; case Q_EVAL: - if (q->query == q->query_buf) + if (command->query == command->query_buf) { - q->query= q->first_argument; - q->first_word_len= 0; + command->query= command->first_argument; + command->first_word_len= 0; } /* fall through */ case Q_QUERY_VERTICAL: case Q_QUERY_HORIZONTAL: { my_bool old_display_result_vertically= display_result_vertically; - /* fix up query pointer if this is first iteration for this line */ - if (q->query == q->query_buf) - q->query += q->first_word_len + 1; - display_result_vertically= (q->type==Q_QUERY_VERTICAL); + + /* Remove "query_*" if this is first iteration */ + if (command->query == command->query_buf) + command->query= command->first_argument; + + display_result_vertically= (command->type == Q_QUERY_VERTICAL); if (save_file[0]) { - strmov(q->record_file,save_file); - q->require_file=require_file; - save_file[0]=0; + strmake(command->require_file, save_file, sizeof(save_file)); + save_file[0]= 0; } - run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); + run_query(&cur_con->mysql, command, QUERY_REAP_FLAG|QUERY_SEND_FLAG); display_result_vertically= old_display_result_vertically; - q->last_argument= q->end; - query_executed= 1; + command->last_argument= command->end; + command_executed++; break; } case Q_QUERY: case Q_REAP: { - /* - We read the result always regardless of the mode for both full - query and read-result only (reap) - */ - int flags = QUERY_REAP; - if (q->type != Q_REAP) /* for a full query, enable the send stage */ - flags |= QUERY_SEND; - if (q_send_flag) - { - flags= QUERY_SEND; - q_send_flag=0; - } + int flags; + if (q_send_flag) + { + /* Last command was an empty 'send' */ + flags= QUERY_SEND_FLAG; + q_send_flag= 0; + } + else if (command->type == Q_REAP) + { + flags= QUERY_REAP_FLAG; + } + else + { + /* full query, both reap and send */ + flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG; + } + if (save_file[0]) { - strmov(q->record_file,save_file); - q->require_file=require_file; - save_file[0]=0; + strmake(command->require_file, save_file, sizeof(save_file)); + save_file[0]= 0; } - /* - To force something being sent as a query to the mysqld one can - use the prefix "query". Remove "query" from string before executing - */ - if (strncmp(q->query, "query ", 6) == 0) - { - q->query= q->first_argument; - } - run_query(&cur_con->mysql, q, flags); - query_executed= 1; - q->last_argument= q->end; + run_query(&cur_con->mysql, command, flags); + command_executed++; + command->last_argument= command->end; break; } case Q_SEND: - if (!q->query[q->first_word_len]) - { - /* This happens when we use 'send' on its own line */ - q_send_flag=1; - break; - } - /* fix up query pointer if this is first iteration for this line */ - if (q->query == q->query_buf) - q->query += q->first_word_len; + if (!*command->first_argument) + { + /* + This is a send without arguments, it indicates that _next_ query + should be send only + */ + q_send_flag= 1; + break; + } + + /* Remove "send" if this is first iteration */ + if (command->query == command->query_buf) + command->query= command->first_argument; + /* run_query() can execute a query partially, depending on the flags. - QUERY_SEND flag without QUERY_REAP tells it to just send the - query and read the result some time later when reap instruction + QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send + the query and read the result some time later when reap instruction is given on this connection. - */ - run_query(&cur_con->mysql, q, QUERY_SEND); - query_executed= 1; - q->last_argument= q->end; + */ + run_query(&cur_con->mysql, command, QUERY_SEND_FLAG); + command_executed++; + command->last_argument= command->end; break; - case Q_RESULT: - get_file_name(save_file,q); - require_file=0; + case Q_REQUIRE: + do_get_file_name(command, save_file, sizeof(save_file)); break; case Q_ERROR: - global_expected_errors=get_errcodes(global_expected_errno,q); - break; - case Q_REQUIRE: - get_file_name(save_file,q); - require_file=1; + do_get_errcodes(command); break; case Q_REPLACE: - get_replace(q); + do_get_replace(command); break; case Q_REPLACE_REGEX: - get_replace_regex(q); + do_get_replace_regex(command); break; - case Q_REPLACE_COLUMN: - get_replace_column(q); + do_get_replace_column(command); break; case Q_SAVE_MASTER_POS: do_save_master_pos(); break; - case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break; + case Q_SYNC_WITH_MASTER: do_sync_with_master(command); break; case Q_SYNC_SLAVE_WITH_MASTER: { do_save_master_pos(); - if (*q->first_argument) - select_connection(q); + if (*command->first_argument) + select_connection(command); else select_connection_name("slave"); do_sync_with_master2(0); break; } case Q_COMMENT: /* Ignore row */ - case Q_COMMENT_WITH_COMMAND: - q->last_argument= q->end; + command->last_argument= command->end; break; case Q_PING: (void) mysql_ping(&cur_con->mysql); break; case Q_EXEC: - do_exec(q); - query_executed= 1; + do_exec(command); + command_executed++; break; case Q_START_TIMER: /* Overwrite possible earlier start of timer */ @@ -5470,10 +5732,9 @@ int main(int argc, char **argv) case Q_END_TIMER: /* End timer before ending mysqltest */ timer_output(); - got_end_timer= TRUE; break; case Q_CHARACTER_SET: - set_charset(q); + do_set_charset(command); break; case Q_DISABLE_PS_PROTOCOL: ps_protocol_enabled= 0; @@ -5482,31 +5743,33 @@ int main(int argc, char **argv) ps_protocol_enabled= ps_protocol; break; case Q_DISABLE_RECONNECT: - { - my_bool reconnect= 0; - mysql_options(&cur_con->mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); + set_reconnect(&cur_con->mysql, 0); break; - } case Q_ENABLE_RECONNECT: - { - my_bool reconnect= 1; - mysql_options(&cur_con->mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); + set_reconnect(&cur_con->mysql, 1); break; - } case Q_DISABLE_PARSING: - parsing_disabled++; + if (parsing_disabled == 0) + parsing_disabled= 1; + else + die("Parsing is already disabled"); break; case Q_ENABLE_PARSING: /* Ensure we don't get parsing_disabled < 0 as this would accidentally disable code we don't want to have disabled */ - if (parsing_disabled > 0) - parsing_disabled--; + if (parsing_disabled == 1) + parsing_disabled= 0; + else + die("Parsing is already enabled"); break; - case Q_DIE: - die("%s", q->first_argument); + die("%s", command->first_argument); + break; + + case Q_RESULT: + die("result, deprecated command"); break; default: @@ -5518,33 +5781,46 @@ int main(int argc, char **argv) if (!processed) { current_line_inc= 0; - switch (q->type) { - case Q_WHILE: do_block(cmd_while, q); break; - case Q_IF: do_block(cmd_if, q); break; - case Q_END_BLOCK: do_done(q); break; + switch (command->type) { + case Q_WHILE: do_block(cmd_while, command); break; + case Q_IF: do_block(cmd_if, command); break; + case Q_END_BLOCK: do_done(command); break; default: current_line_inc = 1; break; } } else - check_eol_junk(q->last_argument); + check_eol_junk(command->last_argument); - if (q->type != Q_ERROR) + if (command->type != Q_ERROR && + command->type != Q_COMMENT) { /* - As soon as any non "error" command has been executed, + As soon as any non "error" command or comment has been executed, the array with expected errors should be cleared */ - global_expected_errors= 0; - bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); + memset(&saved_expected_errors, 0, sizeof(saved_expected_errors)); + } + + if (command_executed != last_command_executed) + { + /* + As soon as any command has been executed, + the replace structures should be cleared + */ + free_all_replace(); } + last_command_executed= command_executed; parser.current_line += current_line_inc; if ( opt_mark_progress ) - mark_progress(q, parser.current_line); + mark_progress(command, parser.current_line); } start_lineno= 0; + if (parsing_disabled) + die("Test ended with parsing disabled"); + /* The whole test has been executed _sucessfully_. Time to compare result or save it to record file. @@ -5552,25 +5828,27 @@ int main(int argc, char **argv) */ if (ds_res.length) { - if (result_file) + if (result_file_name) { + /* A result file has been specified */ + if (record) { - /* Dump the output from test to result file */ - str_to_file(result_file, ds_res.str, ds_res.length); + /* Recording - dump the output from test to result file */ + str_to_file(result_file_name, ds_res.str, ds_res.length); } else { /* Check that the output from test is equal to result file - detect missing result file - detect zero size result file - */ - check_result(&ds_res, result_file, 0); + */ + check_result(&ds_res); } } else { - /* No result_file specified to compare with, print to stdout */ + /* No result_file_name specified to compare with, print to stdout */ printf("%s", ds_res.str); } } @@ -5579,7 +5857,8 @@ int main(int argc, char **argv) die("The test didn't produce any output"); } - if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) + if (!command_executed && + result_file_name && my_stat(result_file_name, &res_info, 0)) { /* my_stat() successful on result file. Check if we have not run a @@ -5591,14 +5870,16 @@ int main(int argc, char **argv) die("No queries executed but result file found!"); } - if ( opt_mark_progress ) - dump_progress(result_file); - dynstr_free(&ds_progress); + if ( opt_mark_progress && result_file_name ) + dump_progress(); + + /* Dump warning messages */ + if (result_file_name && ds_warning_messages.length) + dump_warning_messages(); dynstr_free(&ds_res); - if (!got_end_timer) - timer_output(); /* No end_timer cmd, end it */ + timer_output(); free_used_memory(); my_end(MY_CHECK_ERROR); @@ -5611,101 +5892,188 @@ int main(int argc, char **argv) /* - Read arguments for embedded server and put them into - embedded_server_args_count and embedded_server_args[] -*/ + A primitive timer that give results in milliseconds if the + --timer-file=<filename> is given. The timer result is written + to that file when the result is available. To not confuse + mysql-test-run with an old obsolete result, we remove the file + before executing any commands. The time we measure is + - If no explicit 'start_timer' or 'end_timer' is given in the + test case, the timer measure how long we execute in mysqltest. -static int read_server_arguments(const char *name) -{ - char argument[1024],buff[FN_REFLEN], *str=0; - FILE *file; + - If only 'start_timer' is given we measure how long we execute + from that point until we terminate mysqltest. - if (!test_if_hard_path(name)) + - If only 'end_timer' is given we measure how long we execute + from that we enter mysqltest to the 'end_timer' is command is + executed. + + - If both 'start_timer' and 'end_timer' are given we measure + the time between executing the two commands. +*/ + +void timer_output(void) +{ + if (timer_file) { - strxmov(buff, opt_basedir, name, NullS); - name=buff; + char buf[32], *end; + ulonglong timer= timer_now() - timer_start; + end= longlong2str(timer, buf, 10); + str_to_file(timer_file,buf, (int) (end-buf)); + /* Timer has been written to the file, don't use it anymore */ + timer_file= 0; } - fn_format(buff, name, "", "", MY_UNPACK_FILENAME); +} - if (!embedded_server_arg_count) + +ulonglong timer_now(void) +{ + return my_getsystime() / 10000; +} + + +/* + Get arguments for replace_columns. The syntax is: + replace-column column_number to_string [column_number to_string ...] + Where each argument may be quoted with ' or " + A argument may also be a variable, in which case the value of the + variable is replaced. +*/ + +void do_get_replace_column(struct st_command *command) +{ + char *from= command->first_argument; + char *buff, *start; + DBUG_ENTER("get_replace_columns"); + + free_replace_column(); + if (!*from) + die("Missing argument in %s", command->query); + + /* Allocate a buffer for results */ + start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + while (*from) { - embedded_server_arg_count=1; - embedded_server_args[0]= (char*) ""; /* Progname */ + char *to; + uint column_number; + + to= get_string(&buff, &from, 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); + to= get_string(&buff, &from, command); + my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); + replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); + set_if_bigger(max_replace_column, column_number); } - if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - return 1; - while (embedded_server_arg_count < MAX_SERVER_ARGS && - (str=fgets(argument,sizeof(argument), file))) + my_free(start, MYF(0)); + command->last_argument= command->end; +} + + +void free_replace_column() +{ + uint i; + for (i=0 ; i < max_replace_column ; i++) { - *(strend(str)-1)=0; /* Remove end newline */ - if (!(embedded_server_args[embedded_server_arg_count]= - (char*) my_strdup(str,MYF(MY_WME)))) + if (replace_column[i]) { - my_fclose(file,MYF(0)); - return 1; + my_free(replace_column[i], 0); + replace_column[i]= 0; } - embedded_server_arg_count++; } - my_fclose(file,MYF(0)); - if (str) - { - fprintf(stderr,"Too many arguments in option file: %s\n",name); - return 1; - } - return 0; + max_replace_column= 0; } -/****************************************************************************\ - * - * A primitive timer that give results in milliseconds if the - * --timer-file=<filename> is given. The timer result is written - * to that file when the result is available. To not confuse - * mysql-test-run with an old obsolete result, we remove the file - * before executing any commands. The time we measure is - * - * - If no explicit 'start_timer' or 'end_timer' is given in the - * test case, the timer measure how long we execute in mysqltest. - * - * - If only 'start_timer' is given we measure how long we execute - * from that point until we terminate mysqltest. - * - * - If only 'end_timer' is given we measure how long we execute - * from that we enter mysqltest to the 'end_timer' is command is - * executed. - * - * - If both 'start_timer' and 'end_timer' are given we measure - * the time between executing the two commands. - * -\****************************************************************************/ - -static void timer_output(void) + +/****************************************************************************/ +/* + Replace functions +*/ + +/* Definitions for replace result */ + +typedef struct st_pointer_array { /* when using array-strings */ + TYPELIB typelib; /* Pointer to strings */ + byte *str; /* Strings is here */ + int7 *flag; /* Flag about each var. */ + uint array_allocs,max_count,length,max_length; +} POINTER_ARRAY; + +struct st_replace; +struct st_replace *init_replace(my_string *from, my_string *to, uint count, + my_string word_end_chars); +int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string 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 ...] + Where each argument may be quoted with ' or " + A argument may also be a variable, in which case the value of the + variable is replaced. +*/ + +void do_get_replace(struct st_command *command) { - if (timer_file) + uint i; + char *from= command->first_argument; + char *buff, *start; + char word_end_chars[256], *pos; + POINTER_ARRAY to_array, from_array; + DBUG_ENTER("get_replace"); + + free_replace(); + + bzero((char*) &to_array,sizeof(to_array)); + bzero((char*) &from_array,sizeof(from_array)); + if (!*from) + die("Missing argument in %s", command->query); + start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + while (*from) { - char buf[32], *end; - ulonglong timer= timer_now() - timer_start; - end= longlong2str(timer, buf, 10); - str_to_file(timer_file,buf, (int) (end-buf)); + char *to= buff; + to= get_string(&buff, &from, command); + if (!*from) + die("Wrong number of arguments to replace_result in '%s'", + command->query); + insert_pointer_name(&from_array,to); + to= get_string(&buff, &from, command); + insert_pointer_name(&to_array,to); } + for (i= 1,pos= word_end_chars ; i < 256 ; i++) + if (my_isspace(charset_info,i)) + *pos++= i; + *pos=0; /* End pointer */ + if (!(glob_replace= init_replace((char**) from_array.typelib.type_names, + (char**) to_array.typelib.type_names, + (uint) from_array.typelib.count, + word_end_chars))) + die("Can't initialize replace from '%s'", command->query); + free_pointer_array(&from_array); + free_pointer_array(&to_array); + my_free(start, MYF(0)); + command->last_argument= command->end; + DBUG_VOID_RETURN; } -static ulonglong timer_now(void) + +void free_replace() { - return my_getsystime() / 10000; + DBUG_ENTER("free_replace"); + if (glob_replace) + { + my_free((char*) glob_replace,MYF(0)); + glob_replace=0; + } + DBUG_VOID_RETURN; } -/**************************************************************************** -* Handle replacement of strings -****************************************************************************/ - -#define PC_MALLOC 256 /* Bytes for pointers */ -#define PS_MALLOC 512 /* Bytes for data */ - -#define SPACE_CHAR 256 -#define START_OF_LINE 257 -#define END_OF_LINE 258 -#define LAST_CHAR_CODE 259 typedef struct st_replace { bool found; @@ -5719,99 +6087,514 @@ typedef struct st_replace_found { int from_offset; } REPLACE_STRING; -#ifndef WORD_BIT -#define WORD_BIT (8*sizeof(uint)) -#endif +void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds, + const char *str, int len) +{ + reg1 REPLACE *rep_pos; + reg2 REPLACE_STRING *rep_str; + const char *start, *from; + DBUG_ENTER("replace_strings_append"); + + start= from= str; + rep_pos=rep+1; + for (;;) + { + /* Loop through states */ + DBUG_PRINT("info", ("Looping through states")); + while (!rep_pos->found) + rep_pos= rep_pos->next[(uchar) *from++]; + + /* Does this state contain a string to be replaced */ + if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string) + { + /* No match found */ + dynstr_append_mem(ds, start, from - start - 1); + DBUG_PRINT("exit", ("Found no more string to replace, appended: %s", start)); + DBUG_VOID_RETURN; + } -static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) + /* Found a string that needs to be replaced */ + DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s", + rep_str->found, rep_str->to_offset, + rep_str->from_offset, rep_str->replace_string)); + + /* Append part of original string before replace string */ + dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start); + + /* Append replace string */ + dynstr_append_mem(ds, rep_str->replace_string, + strlen(rep_str->replace_string)); + + if (!*(from-=rep_str->from_offset) && rep_pos->found != 2) + { + /* End of from string */ + DBUG_PRINT("exit", ("Found end of from string")); + DBUG_VOID_RETURN; + } + DBUG_ASSERT(from <= str+len); + start= from; + rep_pos=rep; + } +} + + +/* + Regex replace functions +*/ + + +/* Stores regex substitutions */ + +struct st_regex { - uint i,length,old_count; - byte *new_pos; - const char **new_array; - DBUG_ENTER("insert_pointer_name"); + char* pattern; /* Pattern to be replaced */ + char* replace; /* String or expression to replace the pattern with */ + int icase; /* true if the match is case insensitive */ +}; - if (! pa->typelib.count) +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); + + + +/* + Finds the next (non-escaped) '/' in the expression. + (If the character '/' is needed, it can be escaped using '\'.) +*/ + +#define PARSE_REGEX_ARG \ + while (p < expr_end) \ + { \ + char c= *p; \ + if (c == '/') \ + { \ + if (last_c == '\\') \ + { \ + buf_p[-1]= '/'; \ + } \ + else \ + { \ + *buf_p++ = 0; \ + break; \ + } \ + } \ + else \ + *buf_p++ = c; \ + \ + last_c= c; \ + p++; \ + } \ + \ +/* + Initializes the regular substitution expression to be used in the + result output of test. + + Returns: st_replace_regex struct with pairs of substitutions +*/ + +struct st_replace_regex* init_replace_regex(char* expr) +{ + struct st_replace_regex* res; + char* buf,*expr_end; + char* p; + char* buf_p; + uint expr_len= strlen(expr); + char last_c = 0; + struct st_regex reg; + + /* my_malloc() will die on fail with MY_FAE */ + res=(struct st_replace_regex*)my_malloc( + sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME)); + my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128); + + buf= (char*)res + sizeof(*res); + expr_end= expr + expr_len; + p= expr; + buf_p= buf; + + /* for each regexp substitution statement */ + while (p < expr_end) { - if (!(pa->typelib.type_names=(const char **) - my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/ - (sizeof(my_string)+sizeof(*pa->flag))* - (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME)))) - DBUG_RETURN(-1); - if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), - MYF(MY_WME)))) + bzero(®,sizeof(reg)); + /* find the start of the statement */ + while (p < expr_end) { - my_free((gptr) pa->typelib.type_names,MYF(0)); - DBUG_RETURN (-1); + if (*p == '/') + break; + p++; } - pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+ - sizeof(*pa->flag)); - pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); - pa->length=0; - pa->max_length=PS_MALLOC-MALLOC_OVERHEAD; - pa->array_allocs=1; + + if (p == expr_end || ++p == expr_end) + { + if (res->regex_arr.elements) + break; + else + goto err; + } + /* we found the start */ + reg.pattern= buf_p; + + /* Find first argument -- pattern string to be removed */ + PARSE_REGEX_ARG + + if (p == expr_end || ++p == expr_end) + goto err; + + /* buf_p now points to the replacement pattern terminated with \0 */ + reg.replace= buf_p; + + /* Find second argument -- replace string to replace pattern */ + PARSE_REGEX_ARG + + if (p == expr_end) + goto err; + + /* skip the ending '/' in the statement */ + p++; + + /* Check if we should do matching case insensitive */ + if (p < expr_end && *p == 'i') + reg.icase= 1; + + /* done parsing the statement, now place it in regex_arr */ + if (insert_dynamic(&res->regex_arr,(gptr) ®)) + die("Out of memory"); } - length=(uint) strlen(name)+1; - if (pa->length+length >= pa->max_length) + res->odd_buf_len= res->even_buf_len= 8192; + res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE)); + res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE)); + res->buf= res->even_buf; + + return res; + +err: + my_free((gptr)res,0); + die("Error parsing replace_regex \"%s\"", expr); + return 0; +} + +/* + Execute all substitutions on val. + + Returns: true if substituition was made, false otherwise + Side-effect: Sets r->buf to be the buffer with all substitutions done. + + IN: + struct st_replace_regex* r + char* val + Out: + struct st_replace_regex* r + r->buf points at the resulting buffer + r->even_buf and r->odd_buf might have been reallocated + r->even_buf_len and r->odd_buf_len might have been changed + + TODO: at some point figure out if there is a way to do everything + in one pass +*/ + +int multi_reg_replace(struct st_replace_regex* r,char* val) +{ + uint i; + char* in_buf, *out_buf; + int* buf_len_p; + + in_buf= val; + out_buf= r->even_buf; + buf_len_p= &r->even_buf_len; + r->buf= 0; + + /* For each substitution, do the replace */ + for (i= 0; i < r->regex_arr.elements; i++) { - if (!(new_pos= (byte*) my_realloc((gptr) pa->str, - (uint) (pa->max_length+PS_MALLOC), - MYF(MY_WME)))) - DBUG_RETURN(1); - if (new_pos != pa->str) + struct st_regex re; + char* save_out_buf= out_buf; + + get_dynamic(&r->regex_arr,(gptr)&re,i); + + if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace, + in_buf, re.icase)) { - my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str); - for (i=0 ; i < pa->typelib.count ; i++) - pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff, - char*); - pa->str=new_pos; + /* if the buffer has been reallocated, make adjustements */ + if (save_out_buf != out_buf) + { + if (save_out_buf == r->even_buf) + r->even_buf= out_buf; + else + r->odd_buf= out_buf; + } + + r->buf= out_buf; + if (in_buf == val) + in_buf= r->odd_buf; + + swap_variables(char*,in_buf,out_buf); + + buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len : + &r->odd_buf_len; } - pa->max_length+=PS_MALLOC; } - if (pa->typelib.count >= pa->max_count-1) + + return (r->buf == 0); +} + +/* + Parse the regular expression to be used in all result files + from now on. + + The syntax is --replace_regex /from/to/i /from/to/i ... + i means case-insensitive match. If omitted, the match is + case-sensitive + +*/ +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))) + die("Could not init replace_regex"); + command->last_argument= command->end; +} + +void free_replace_regex() +{ + if (glob_replace_regex) { - int len; - pa->array_allocs++; - len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD); - if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names, - (uint) len/ - (sizeof(byte*)+sizeof(*pa->flag))* - (sizeof(byte*)+sizeof(*pa->flag)), - MYF(MY_WME)))) - DBUG_RETURN(1); - pa->typelib.type_names=new_array; - old_count=pa->max_count; - pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag)); - pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); - memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count), - old_count*sizeof(*pa->flag)); + 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((char*) glob_replace_regex,MYF(0)); + glob_replace_regex=0; } - pa->flag[pa->typelib.count]=0; /* Reset flag */ - pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length; - pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */ - VOID(strmov(pa->str+pa->length,name)); - pa->length+=length; - DBUG_RETURN(0); -} /* insert_pointer_name */ +} - /* free pointer array */ -void free_pointer_array(POINTER_ARRAY *pa) +/* + auxiluary macro used by reg_replace + makes sure the result buffer has sufficient length +*/ +#define SECURE_REG_BUF if (buf_len < need_buf_len) \ + { \ + int off= res_p - buf; \ + buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE)); \ + res_p= buf + off; \ + buf_len= need_buf_len; \ + } \ + \ +/* + Performs a regex substitution + + IN: + + buf_p - result buffer pointer. Will change if reallocated + buf_len_p - result buffer length. Will change if the buffer is reallocated + pattern - regexp pattern to match + replace - replacement expression + string - the string to perform substituions in + icase - flag, if set to 1 the match is case insensitive +*/ +int reg_replace(char** buf_p, int* buf_len_p, char *pattern, + char *replace, char *string, int icase) { - if (pa->typelib.count) + my_regex_t r; + my_regmatch_t *subs; + char *buf_end, *replace_end; + char *buf= *buf_p; + int len; + int buf_len, need_buf_len; + int cflags= REG_EXTENDED; + int err_code; + char *res_p,*str_p,*str_end; + + buf_len= *buf_len_p; + len= strlen(string); + str_end= string + len; + + /* start with a buffer of a reasonable size that hopefully will not + need to be reallocated + */ + need_buf_len= len * 2 + 1; + res_p= buf; + + SECURE_REG_BUF + + buf_end= buf + buf_len; + + if (icase) + cflags|= REG_ICASE; + + if ((err_code= my_regcomp(&r,pattern,cflags,&my_charset_latin1))) { - pa->typelib.count=0; - my_free((gptr) pa->typelib.type_names,MYF(0)); - pa->typelib.type_names=0; - my_free((gptr) pa->str,MYF(0)); + check_regerr(&r,err_code); + return 1; } -} /* free_pointer_array */ + subs= (my_regmatch_t*)my_malloc(sizeof(my_regmatch_t) * (r.re_nsub+1), + MYF(MY_WME+MY_FAE)); + + *res_p= 0; + str_p= string; + replace_end= replace + strlen(replace); + + /* for each pattern match instance perform a replacement */ + while (!err_code) + { + /* find the match */ + err_code= my_regexec(&r,str_p, r.re_nsub+1, subs, + (str_p == string) ? REG_NOTBOL : 0); + + /* if regular expression error (eg. bad syntax, or out of memory) */ + if (err_code && err_code != REG_NOMATCH) + { + check_regerr(&r,err_code); + my_regfree(&r); + return 1; + } + + /* if match found */ + if (!err_code) + { + char* expr_p= replace; + int c; + + /* + we need at least what we have so far in the buffer + the part + before this match + */ + need_buf_len= (res_p - buf) + subs[0].rm_so; + + /* on this pass, calculate the memory for the result buffer */ + while (expr_p < replace_end) + { + int back_ref_num= -1; + c= *expr_p; + + if (c == '\\' && expr_p + 1 < replace_end) + { + back_ref_num= expr_p[1] - '0'; + } + + /* found a valid back_ref (eg. \1)*/ + if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) + { + int start_off,end_off; + if ((start_off=subs[back_ref_num].rm_so) > -1 && + (end_off=subs[back_ref_num].rm_eo) > -1) + { + need_buf_len += (end_off - start_off); + } + expr_p += 2; + } + else + { + expr_p++; + need_buf_len++; + } + } + need_buf_len++; + /* + now that we know the size of the buffer, + make sure it is big enough + */ + SECURE_REG_BUF + + /* copy the pre-match part */ + if (subs[0].rm_so) + { + memcpy(res_p, str_p, subs[0].rm_so); + res_p+= subs[0].rm_so; + } + + expr_p= replace; + + /* copy the match and expand back_refs */ + while (expr_p < replace_end) + { + int back_ref_num= -1; + c= *expr_p; + + if (c == '\\' && expr_p + 1 < replace_end) + { + back_ref_num= expr_p[1] - '0'; + } - /* Code for replace rutines */ + if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) + { + int start_off,end_off; + if ((start_off=subs[back_ref_num].rm_so) > -1 && + (end_off=subs[back_ref_num].rm_eo) > -1) + { + int block_len= end_off - start_off; + memcpy(res_p,str_p + start_off, block_len); + res_p += block_len; + } + expr_p += 2; + } + else + { + *res_p++ = *expr_p++; + } + } + + /* handle the post-match part */ + if (subs[0].rm_so == subs[0].rm_eo) + { + if (str_p + subs[0].rm_so >= str_end) + break; + str_p += subs[0].rm_eo ; + *res_p++ = *str_p++; + } + else + { + str_p += subs[0].rm_eo; + } + } + else /* no match this time, just copy the string as is */ + { + int left_in_str= str_end-str_p; + need_buf_len= (res_p-buf) + left_in_str; + SECURE_REG_BUF + memcpy(res_p,str_p,left_in_str); + res_p += left_in_str; + str_p= str_end; + } + } + my_free((gptr)subs, MYF(0)); + my_regfree(&r); + *res_p= 0; + *buf_p= buf; + *buf_len_p= buf_len; + return 0; +} + + +#ifndef WORD_BIT +#define WORD_BIT (8*sizeof(uint)) +#endif #define SET_MALLOC_HUNC 64 +#define LAST_CHAR_CODE 259 typedef struct st_rep_set { uint *bits; /* Pointer to used sets */ @@ -5843,32 +6626,48 @@ typedef struct st_follow { } FOLLOWS; -static int init_sets(REP_SETS *sets,uint states); -static REP_SET *make_new_set(REP_SETS *sets); -static void make_sets_invisible(REP_SETS *sets); -static void free_last_set(REP_SETS *sets); -static void free_sets(REP_SETS *sets); -static void internal_set_bit(REP_SET *set, uint bit); -static void internal_clear_bit(REP_SET *set, uint bit); -static void or_bits(REP_SET *to,REP_SET *from); -static void copy_bits(REP_SET *to,REP_SET *from); -static int cmp_bits(REP_SET *set1,REP_SET *set2); -static int get_next_bit(REP_SET *set,uint lastpos); -static int find_set(REP_SETS *sets,REP_SET *find); -static int find_found(FOUND_SET *found_set,uint table_offset, - int found_offset); -static uint start_at_word(my_string pos); -static uint end_of_word(my_string pos); -static uint replace_len(my_string pos); +int init_sets(REP_SETS *sets,uint states); +REP_SET *make_new_set(REP_SETS *sets); +void make_sets_invisible(REP_SETS *sets); +void free_last_set(REP_SETS *sets); +void free_sets(REP_SETS *sets); +void internal_set_bit(REP_SET *set, uint bit); +void internal_clear_bit(REP_SET *set, uint bit); +void or_bits(REP_SET *to,REP_SET *from); +void copy_bits(REP_SET *to,REP_SET *from); +int cmp_bits(REP_SET *set1,REP_SET *set2); +int get_next_bit(REP_SET *set,uint lastpos); +int find_set(REP_SETS *sets,REP_SET *find); +int find_found(FOUND_SET *found_set,uint table_offset, + int found_offset); +uint start_at_word(my_string pos); +uint end_of_word(my_string pos); static uint found_sets=0; - /* Init a replace structure for further calls */ +uint replace_len(my_string str) +{ + uint len=0; + while (*str) + { + if (str[0] == '\\' && str[1]) + str++; + str++; + len++; + } + return len; +} + +/* Init a replace structure for further calls */ REPLACE *init_replace(my_string *from, my_string *to,uint count, my_string word_end_chars) { + static const int SPACE_CHAR= 256; + static const int START_OF_LINE= 257; + static const int END_OF_LINE= 258; + uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr; int used_sets,chr,default_state; char used_chars[LAST_CHAR_CODE],is_word_end[256]; @@ -5921,7 +6720,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, DBUG_RETURN(0); } - /* Init follow_ptr[] */ + /* Init follow_ptr[] */ for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++) { if (from[i][0] == '\\' && from[i][1] == '^') @@ -6104,7 +6903,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, } } - /* Alloc replace structure for the replace-state-machine */ + /* Alloc replace structure for the replace-state-machine */ if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+ sizeof(REPLACE_STRING)*(found_sets+1)+ @@ -6147,7 +6946,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, } -static int init_sets(REP_SETS *sets,uint states) +int init_sets(REP_SETS *sets,uint states) { bzero((char*) sets,sizeof(*sets)); sets->size_of_bits=((states+7)/8); @@ -6163,16 +6962,16 @@ static int init_sets(REP_SETS *sets,uint states) return 0; } - /* Make help sets invisible for nicer codeing */ +/* Make help sets invisible for nicer codeing */ -static void make_sets_invisible(REP_SETS *sets) +void make_sets_invisible(REP_SETS *sets) { sets->invisible=sets->count; sets->set+=sets->count; sets->count=0; } -static REP_SET *make_new_set(REP_SETS *sets) +REP_SET *make_new_set(REP_SETS *sets) { uint i,count,*bit_buffer; REP_SET *set; @@ -6190,7 +6989,7 @@ static REP_SET *make_new_set(REP_SETS *sets) } count=sets->count+sets->invisible+SET_MALLOC_HUNC; if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer, - sizeof(REP_SET)*count, + sizeof(REP_SET)*count, MYF(MY_WME)))) return 0; sets->set_buffer=set; @@ -6209,34 +7008,34 @@ static REP_SET *make_new_set(REP_SETS *sets) return make_new_set(sets); } -static void free_last_set(REP_SETS *sets) +void free_last_set(REP_SETS *sets) { sets->count--; sets->extra++; return; } -static void free_sets(REP_SETS *sets) +void free_sets(REP_SETS *sets) { my_free((gptr)sets->set_buffer,MYF(0)); my_free((gptr)sets->bit_buffer,MYF(0)); return; } -static void internal_set_bit(REP_SET *set, uint bit) +void internal_set_bit(REP_SET *set, uint bit) { set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT); return; } -static void internal_clear_bit(REP_SET *set, uint bit) +void internal_clear_bit(REP_SET *set, uint bit) { set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT)); return; } -static void or_bits(REP_SET *to,REP_SET *from) +void or_bits(REP_SET *to,REP_SET *from) { reg1 uint i; for (i=0 ; i < to->size_of_bits ; i++) @@ -6244,22 +7043,22 @@ static void or_bits(REP_SET *to,REP_SET *from) return; } -static void copy_bits(REP_SET *to,REP_SET *from) +void copy_bits(REP_SET *to,REP_SET *from) { memcpy((byte*) to->bits,(byte*) from->bits, (size_t) (sizeof(uint) * to->size_of_bits)); } -static int cmp_bits(REP_SET *set1,REP_SET *set2) +int cmp_bits(REP_SET *set1,REP_SET *set2) { return bcmp((byte*) set1->bits,(byte*) set2->bits, sizeof(uint) * set1->size_of_bits); } - /* Get next set bit from set. */ +/* Get next set bit from set. */ -static int get_next_bit(REP_SET *set,uint lastpos) +int get_next_bit(REP_SET *set,uint lastpos) { uint pos,*start,*end,bits; @@ -6280,11 +7079,11 @@ static int get_next_bit(REP_SET *set,uint lastpos) return pos; } - /* find if there is a same set in sets. If there is, use it and - free given set, else put in given set in sets and return its - position */ +/* find if there is a same set in sets. If there is, use it and + free given set, else put in given set in sets and return its + position */ -static int find_set(REP_SETS *sets,REP_SET *find) +int find_set(REP_SETS *sets,REP_SET *find) { uint i; for (i=0 ; i < sets->count-1 ; i++) @@ -6298,14 +7097,14 @@ static int find_set(REP_SETS *sets,REP_SET *find) return i; /* return new postion */ } - /* find if there is a found_set with same table_offset & found_offset - If there is return offset to it, else add new offset and return pos. - Pos returned is -offset-2 in found_set_structure because it is - saved in set->next and set->next[] >= 0 points to next set and - set->next[] == -1 is reserved for end without replaces. - */ +/* find if there is a found_set with same table_offset & found_offset + If there is return offset to it, else add new offset and return pos. + Pos returned is -offset-2 in found_set_structure because it is + saved in set->next and set->next[] >= 0 points to next set and + set->next[] == -1 is reserved for end without replaces. +*/ -static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) +int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) { int i; for (i=0 ; (uint) i < found_sets ; i++) @@ -6318,145 +7117,155 @@ static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) return -i-2; /* return new postion */ } - /* Return 1 if regexp starts with \b or ends with \b*/ +/* Return 1 if regexp starts with \b or ends with \b*/ -static uint start_at_word(my_string pos) +uint start_at_word(my_string pos) { return (((!bcmp(pos,"\\b",2) && pos[2]) || !bcmp(pos,"\\^",2)) ? 1 : 0); } -static uint end_of_word(my_string pos) +uint end_of_word(my_string pos) { my_string end=strend(pos); return ((end > pos+2 && !bcmp(end-2,"\\b",2)) || (end >= pos+2 && !bcmp(end-2,"\\$",2))) ? - 1 : 0; + 1 : 0; } +/**************************************************************************** + * Handle replacement of strings + ****************************************************************************/ -static uint replace_len(my_string str) -{ - uint len=0; - while (*str) - { - if (str[0] == '\\' && str[1]) - str++; - str++; - len++; - } - return len; -} - +#define PC_MALLOC 256 /* Bytes for pointers */ +#define PS_MALLOC 512 /* Bytes for data */ -/* Replace strings while appending to ds */ -void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds, - const char *str, int len) +int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) { - reg1 REPLACE *rep_pos; - reg2 REPLACE_STRING *rep_str; - const char *start, *from; - DBUG_ENTER("replace_strings_append"); + uint i,length,old_count; + byte *new_pos; + const char **new_array; + DBUG_ENTER("insert_pointer_name"); - start= from= str; - rep_pos=rep+1; - for (;;) + if (! pa->typelib.count) { - /* Loop through states */ - DBUG_PRINT("info", ("Looping through states")); - while (!rep_pos->found) - rep_pos= rep_pos->next[(uchar) *from++]; - - /* Does this state contain a string to be replaced */ - if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string) + if (!(pa->typelib.type_names=(const char **) + my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/ + (sizeof(my_string)+sizeof(*pa->flag))* + (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME)))) + DBUG_RETURN(-1); + if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), + MYF(MY_WME)))) { - /* No match found */ - dynstr_append_mem(ds, start, from - start - 1); - DBUG_PRINT("exit", ("Found no more string to replace, appended: %s", start)); - DBUG_VOID_RETURN; + my_free((gptr) pa->typelib.type_names,MYF(0)); + DBUG_RETURN (-1); } - - /* Found a string that needs to be replaced */ - DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s", - rep_str->found, rep_str->to_offset, - rep_str->from_offset, rep_str->replace_string)); - - /* Append part of original string before replace string */ - dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start); - - /* Append replace string */ - dynstr_append_mem(ds, rep_str->replace_string, - strlen(rep_str->replace_string)); - - if (!*(from-=rep_str->from_offset) && rep_pos->found != 2) + pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+ + sizeof(*pa->flag)); + pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); + pa->length=0; + pa->max_length=PS_MALLOC-MALLOC_OVERHEAD; + pa->array_allocs=1; + } + length=(uint) strlen(name)+1; + if (pa->length+length >= pa->max_length) + { + if (!(new_pos= (byte*) my_realloc((gptr) pa->str, + (uint) (pa->max_length+PS_MALLOC), + MYF(MY_WME)))) + DBUG_RETURN(1); + if (new_pos != pa->str) { - /* End of from string */ - DBUG_PRINT("exit", ("Found end of from string")); - DBUG_VOID_RETURN; + my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str); + for (i=0 ; i < pa->typelib.count ; i++) + pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff, + char*); + pa->str=new_pos; } - DBUG_ASSERT(from <= str+len); - start= from; - rep_pos=rep; + pa->max_length+=PS_MALLOC; } -} + if (pa->typelib.count >= pa->max_count-1) + { + int len; + pa->array_allocs++; + len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD); + if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names, + (uint) len/ + (sizeof(byte*)+sizeof(*pa->flag))* + (sizeof(byte*)+sizeof(*pa->flag)), + MYF(MY_WME)))) + DBUG_RETURN(1); + pa->typelib.type_names=new_array; + old_count=pa->max_count; + pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag)); + pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); + memcpy((byte*) pa->flag,(my_string) (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++]= pa->str+pa->length; + pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */ + VOID(strmov(pa->str+pa->length,name)); + pa->length+=length; + DBUG_RETURN(0); +} /* insert_pointer_name */ -/**************************************************************************** - Replace results for a column -*****************************************************************************/ +/* free pointer array */ -static void free_replace_column() +void free_pointer_array(POINTER_ARRAY *pa) { - uint i; - for (i=0 ; i < max_replace_column ; i++) + if (pa->typelib.count) { - if (replace_column[i]) - { - my_free(replace_column[i], 0); - replace_column[i]= 0; - } + pa->typelib.count=0; + my_free((gptr) pa->typelib.type_names,MYF(0)); + pa->typelib.type_names=0; + my_free((gptr) pa->str,MYF(0)); } - max_replace_column= 0; -} +} /* free_pointer_array */ -/* - Get arguments for replace_columns. The syntax is: - replace-column column_number to_string [column_number to_string ...] - Where each argument may be quoted with ' or " - A argument may also be a variable, in which case the value of the - variable is replaced. -*/ -static void get_replace_column(struct st_query *q) -{ - char *from=q->first_argument; - char *buff,*start; - DBUG_ENTER("get_replace_columns"); +/* Functions that uses replace and replace_regex */ - free_replace_column(); - if (!*from) - die("Missing argument in %s", q->query); +/* Append the string to ds, with optional replace */ +void replace_dynstr_append_mem(DYNAMIC_STRING *ds, + const char *val, int len) +{ +#ifdef __WIN__ + fix_win_paths(val, len); +#endif - /* Allocate a buffer for results */ - start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); - while (*from) + if (glob_replace_regex) { - char *to; - uint column_number; + /* Regex replace */ + if (!multi_reg_replace(glob_replace_regex, (char*)val)) + { + val= glob_replace_regex->buf; + len= strlen(val); + } + } - to= get_string(&buff, &from, q); - if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) - die("Wrong column number to replace_column in '%s'", q->query); - if (!*from) - die("Wrong number of arguments to replace_column in '%s'", q->query); - to= get_string(&buff, &from, q); - my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); - replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); - set_if_bigger(max_replace_column, column_number); + if (glob_replace) + { + /* Normal replace */ + replace_strings_append(glob_replace, ds, val, len); } - my_free(start, MYF(0)); - q->last_argument= q->end; + else + dynstr_append_mem(ds, val, len); } +/* Append zero-terminated string to ds, with optional replace */ +void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val) +{ + replace_dynstr_append_mem(ds, val, strlen(val)); +} + +/* Append uint to ds, with optional replace */ +void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val) +{ + char buff[22]; /* This should be enough for any int */ + char *end= longlong10_to_str(val, buff, 10); + replace_dynstr_append_mem(ds, buff, end - buff); +} diff --git a/include/my_time.h b/include/my_time.h index d0f2fc323d8..069cecc7b14 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -57,6 +57,16 @@ typedef long my_time_t; #define TIME_NO_ZERO_DATE (TIME_NO_ZERO_IN_DATE*2) #define TIME_INVALID_DATES (TIME_NO_ZERO_DATE*2) +#define MYSQL_TIME_WARN_TRUNCATED 1 +#define MYSQL_TIME_WARN_OUT_OF_RANGE 2 + +/* Limits for the TIME data type */ +#define TIME_MAX_HOUR 838 +#define TIME_MAX_MINUTE 59 +#define TIME_MAX_SECOND 59 +#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + \ + TIME_MAX_SECOND) + enum enum_mysql_timestamp_type str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, uint flags, int *was_cut); @@ -69,7 +79,9 @@ ulonglong TIME_to_ulonglong(const MYSQL_TIME *time); my_bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time, - int *was_cut); + int *warning); + +int check_time_range(struct st_mysql_time *time, int *warning); long calc_daynr(uint year,uint month,uint day); uint calc_days_in_year(uint year); @@ -97,15 +109,25 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to); int my_datetime_to_str(const MYSQL_TIME *l_time, char *to); int my_TIME_to_str(const MYSQL_TIME *l_time, char *to); -/* - The following must be sorted so that simple intervals comes first. - (get_interval_value() depends on this) +/* + Available interval types used in any statement. + + 'interval_type' must be sorted so that simple intervals comes first, + ie year, quarter, month, week, day, hour, etc. The order based on + interval size is also important and the intervals should be kept in a + large to smaller order. (get_interval_value() depends on this) + + Note: If you change the order of elements in this enum you should fix + order of elements in 'interval_type_to_name' and 'interval_names' + arrays + + See also interval_type_to_name, get_interval_value, interval_names */ enum interval_type { - INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, - INTERVAL_MINUTE, INTERVAL_WEEK, INTERVAL_SECOND, INTERVAL_MICROSECOND , + INTERVAL_YEAR, INTERVAL_QUARTER, INTERVAL_MONTH, INTERVAL_WEEK, INTERVAL_DAY, + INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND, INTERVAL_MICROSECOND, INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, INTERVAL_HOUR_MICROSECOND, diff --git a/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test b/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test index 7a097fd1eae..ee6b0ed1426 100644 --- a/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test +++ b/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test @@ -7,6 +7,8 @@ -- source include/master-slave.inc +let $SERVER_VERSION=`select version()`; + create table t1 (a int); insert into t1 values (10); create table t2 (a int); diff --git a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test index 1e485baca36..7f1506c4010 100644 --- a/mysql-test/extra/rpl_tests/rpl_truncate_helper.test +++ b/mysql-test/extra/rpl_tests/rpl_truncate_helper.test @@ -36,6 +36,7 @@ SELECT * FROM t1; --echo **** On Master **** connection master; DROP TABLE t1; +let $SERVER_VERSION=`select version()`; --replace_result $SERVER_VERSION SERVER_VERSION --replace_regex /\/\* xid=[0-9]+ \*\//\/* xid= *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS; diff --git a/mysql-test/include/ctype_like_escape.inc b/mysql-test/include/ctype_like_escape.inc index ac97fbaa1a0..d4abc33c178 100644 --- a/mysql-test/include/ctype_like_escape.inc +++ b/mysql-test/include/ctype_like_escape.inc @@ -11,8 +11,8 @@ insert into t1 values('ab_def'); insert into t1 values('abc_ef'); insert into t1 values('abcd_f'); insert into t1 values('abcde_'); --- should return ab_def +# should return ab_def select c1 as c1u from t1 where c1 like 'ab\_def'; --- should return ab_def +# should return ab_def select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; drop table t1; diff --git a/mysql-test/include/mysqltest_while.inc b/mysql-test/include/mysqltest_while.inc deleted file mode 100644 index 90b05ee2695..00000000000 --- a/mysql-test/include/mysqltest_while.inc +++ /dev/null @@ -1,137 +0,0 @@ -let $1 = 10; -while ($1) -{ -while ($1) -{ -while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - while ($1) -{ - echo $1; - dec $1; -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} -} diff --git a/mysql-test/include/sourced.inc b/mysql-test/include/sourced.inc deleted file mode 100644 index be1a270641a..00000000000 --- a/mysql-test/include/sourced.inc +++ /dev/null @@ -1 +0,0 @@ -echo here is the sourced script; diff --git a/mysql-test/include/sourced1.inc b/mysql-test/include/sourced1.inc deleted file mode 100644 index 920561e5de2..00000000000 --- a/mysql-test/include/sourced1.inc +++ /dev/null @@ -1 +0,0 @@ ---source include/sourced.inc diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index bb92730444c..e6980a0abb9 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -143,7 +143,7 @@ sub collect_test_cases ($) { { next; } - + next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled, @@ -152,43 +152,79 @@ sub collect_test_cases ($) { closedir TESTDIR; } - # To speed things up, we sort first in if the test require a restart - # or not, second in alphanumeric order. - + # Reorder the test cases in an order that wil make them faster to run if ( $::opt_reorder ) { my %sort_criteria; - my $tinfo; # Make a mapping of test name to a string that represents how that test # should be sorted among the other tests. Put the most important criterion # first, then a sub-criterion, then sub-sub-criterion, et c. - foreach $tinfo (@$cases) + foreach my $tinfo (@$cases) { - my @this_criteria = (); - - # Append the criteria for sorting, in order of importance. - push(@this_criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); # Ending with "~" makes empty sort later than filled - push(@this_criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); - push(@this_criteria, "restart=" . ($tinfo->{'master_restart'} ? "1" : "0")); - push(@this_criteria, "big_test=" . ($tinfo->{'big_test'} ? "1" : "0")); - push(@this_criteria, join("|", sort keys %{$tinfo})); # Group similar things together. The values may differ substantially. FIXME? - push(@this_criteria, $tinfo->{'name'}); # Finally, order by the name - - $sort_criteria{$tinfo->{"name"}} = join(" ", @this_criteria); + my @criteria = (); + + # Look for tests that muct be in run in a defined order + # that is defined by test having the same name except for + # the ending digit + + # Put variables into hash + my $test_name= $tinfo->{'name'}; + my $depend_on_test_name; + if ( $test_name =~ /^([\D]+)([0-9]{1})$/ ) + { + my $base_name= $1; + my $idx= $2; + mtr_verbose("$test_name => $base_name idx=$idx"); + if ( $idx > 1 ) + { + $idx-= 1; + $base_name= "$base_name$idx"; + mtr_verbose("New basename $base_name"); + } + + foreach my $tinfo2 (@$cases) + { + if ( $tinfo2->{'name'} eq $base_name ) + { + mtr_verbose("found dependent test $tinfo2->{'name'}"); + $depend_on_test_name=$base_name; + } + } + } + + if ( defined $depend_on_test_name ) + { + mtr_verbose("Giving $test_name same critera as $depend_on_test_name"); + $sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name}; + } + else + { + # + # Append the criteria for sorting, in order of importance. + # + push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); + # Group test with equal options together. + # Ending with "~" makes empty sort later than filled + push(@criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); + + $sort_criteria{$test_name} = join(" ", @criteria); + } } - @$cases = sort { $sort_criteria{$a->{"name"}} cmp $sort_criteria{$b->{"name"}}; } @$cases; + @$cases = sort { + $sort_criteria{$a->{'name'}} . $a->{'name'} cmp + $sort_criteria{$b->{'name'}} . $b->{'name'}; } @$cases; -### For debugging the sort-order -# foreach $tinfo (@$cases) -# { -# print $sort_criteria{$tinfo->{"name"}}; -# print " -> \t"; -# print $tinfo->{"name"}; -# print "\n"; -# } + if ( $::opt_script_debug ) + { + # For debugging the sort-order + foreach my $tinfo (@$cases) + { + print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n"); + } + } } return $cases; @@ -245,6 +281,7 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'path'}= $path; $tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work + $tinfo->{'slave_num'}= 0; # Default, no slave if ( defined mtr_match_prefix($tname,"rpl") ) { if ( $::opt_skip_rpl ) @@ -254,7 +291,8 @@ sub collect_one_test_case($$$$$$$) { return; } - $tinfo->{'slave_num'}= 1; # Default, use one slave + + $tinfo->{'slave_num'}= 1; # Default for rpl* tests, use one slave if ( $tname eq 'rpl_failsafe' or $tname eq 'rpl_chain_temp_table' ) { @@ -272,18 +310,18 @@ sub collect_one_test_case($$$$$$$) { { # This is an ndb test or all tests should be run with ndb cluster started $tinfo->{'ndb_test'}= 1; - if ( $::opt_skip_ndbcluster ) + if ( ! $::opt_ndbcluster_supported ) { - # All ndb test's should be skipped + # Ndb is not supported, skip them $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "No ndbcluster test(--skip-ndbcluster)"; + $tinfo->{'comment'}= "No ndbcluster support"; return; } - if ( ! $::opt_ndbcluster_supported ) + elsif ( $::opt_skip_ndbcluster ) { - # Ndb is not supported, skip them + # All ndb test's should be skipped $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "No ndbcluster support"; + $tinfo->{'comment'}= "No ndbcluster tests(--skip-ndbcluster)"; return; } } @@ -316,57 +354,58 @@ sub collect_one_test_case($$$$$$$) { if ( -f $master_opt_file ) { - $tinfo->{'master_restart'}= 1; # We think so for now - MASTER_OPT: - { - my $master_opt= mtr_get_opts_from_file($master_opt_file); + my $master_opt= mtr_get_opts_from_file($master_opt_file); - foreach my $opt ( @$master_opt ) - { - my $value; + foreach my $opt ( @$master_opt ) + { + my $value; - # This is a dirty hack from old mysql-test-run, we use the opt - # file to flag other things as well, it is not a opt list at - # all + # The opt file is used both to send special options to the mysqld + # as well as pass special test case specific options to this + # script - $value= mtr_match_prefix($opt, "--timezone="); - if ( defined $value ) - { - $tinfo->{'timezone'}= $value; - last MASTER_OPT; - } + $value= mtr_match_prefix($opt, "--timezone="); + if ( defined $value ) + { + $tinfo->{'timezone'}= $value; + next; + } - $value= mtr_match_prefix($opt, "--result-file="); - if ( defined $value ) - { - $tinfo->{'result_file'}= "r/$value.result"; - if ( $::opt_result_ext and $::opt_record or - -f "$tinfo->{'result_file'}$::opt_result_ext") - { - $tinfo->{'result_file'}.= $::opt_result_ext; - } - $tinfo->{'master_restart'}= 0; - last MASTER_OPT; - } + $value= mtr_match_prefix($opt, "--result-file="); + if ( defined $value ) + { + # Specifies the file mysqltest should compare + # output against + $tinfo->{'result_file'}= "r/$value.result"; + next; + } - # If we set default time zone, remove the one we have - $value= mtr_match_prefix($opt, "--default-time-zone="); - if ( defined $value ) - { - $tinfo->{'master_opt'}= []; - } + # If we set default time zone, remove the one we have + $value= mtr_match_prefix($opt, "--default-time-zone="); + if ( defined $value ) + { + $tinfo->{'timezone'}= ""; + # Fallthrough, add this option + } + # The --restart option forces a restart even if no special + # option is set. If the options are the same as next testcase + # there is no need to restart after the testcase + # has completed + if ( $opt eq "--force-restart" ) + { + $tinfo->{'force_restart'}= 1; + next; } - # Ok, this was a real option list, add it - push(@{$tinfo->{'master_opt'}}, @$master_opt); + # Ok, this was a real option, add it + push(@{$tinfo->{'master_opt'}}, $opt); } } if ( -f $slave_opt_file ) { - $tinfo->{'slave_restart'}= 1; my $slave_opt= mtr_get_opts_from_file($slave_opt_file); foreach my $opt ( @$slave_opt ) @@ -381,7 +420,6 @@ sub collect_one_test_case($$$$$$$) { if ( -f $slave_mi_file ) { $tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file); - $tinfo->{'slave_restart'}= 1; } if ( -f $master_sh ) @@ -395,7 +433,6 @@ sub collect_one_test_case($$$$$$$) { else { $tinfo->{'master_sh'}= $master_sh; - $tinfo->{'master_restart'}= 1; } } @@ -410,7 +447,6 @@ sub collect_one_test_case($$$$$$$) { else { $tinfo->{'slave_sh'}= $slave_sh; - $tinfo->{'slave_restart'}= 1; } } @@ -515,17 +551,6 @@ sub collect_one_test_case($$$$$$$) { return; } } - - # We can't restart a running server that may be in use - - if ( $::glob_use_running_server and - ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) ) - { - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "Can't restart a running server"; - return; - } - } diff --git a/mysql-test/lib/mtr_gcov.pl b/mysql-test/lib/mtr_gcov.pl index 07aac1d2017..71d3d6a2a43 100644 --- a/mysql-test/lib/mtr_gcov.pl +++ b/mysql-test/lib/mtr_gcov.pl @@ -23,12 +23,28 @@ sub gcov_prepare () { -or -name \*.da | xargs rm`; } +# Used by gcov +our @mysqld_src_dirs= + ( + "strings", + "mysys", + "include", + "extra", + "regex", + "isam", + "merge", + "myisam", + "myisammrg", + "heap", + "sql", + ); + sub gcov_collect () { print "Collecting source coverage info...\n"; -f $::opt_gcov_msg and unlink($::opt_gcov_msg); -f $::opt_gcov_err and unlink($::opt_gcov_err); - foreach my $d ( @::mysqld_src_dirs ) + foreach my $d ( @mysqld_src_dirs ) { chdir("$::glob_basedir/$d"); foreach my $f ( (glob("*.h"), glob("*.cc"), glob("*.c")) ) diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl index e8dcb0262c9..a1d7ffe87d8 100644 --- a/mysql-test/lib/mtr_io.pl +++ b/mysql-test/lib/mtr_io.pl @@ -12,6 +12,7 @@ sub mtr_fromfile ($); sub mtr_tofile ($@); sub mtr_tonewfile($@); sub mtr_lastlinefromfile($); +sub mtr_appendfile_to_file ($$); ############################################################################## # @@ -170,4 +171,17 @@ sub mtr_tonewfile ($@) { close FILE; } +sub mtr_appendfile_to_file ($$) { + my $from_file= shift; + my $to_file= shift; + + open(TOFILE,">>",$to_file) or mtr_error("can't open file \"$to_file\": $!"); + open(FROMFILE,"<",$from_file) + or mtr_error("can't open file \"$from_file\": $!"); + print TOFILE while (<FROMFILE>); + close FROMFILE; + close TOFILE; +} + + 1; diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 868b6d4f1ec..2831c179ea5 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -4,7 +4,6 @@ # and is part of the translation of the Bourne shell script with the # same name. -#use Carp qw(cluck); use Socket; use Errno; use strict; @@ -93,8 +92,6 @@ sub spawn_impl ($$$$$$$$) { my $pid_file= shift; # FIXME my $spawn_opts= shift; - mtr_error("Can't spawn with empty \"path\"") unless defined $path; - if ( $::opt_script_debug ) { print STDERR "\n"; @@ -118,6 +115,9 @@ sub spawn_impl ($$$$$$$$) { print STDERR "#### ", "-" x 78, "\n"; } + mtr_error("Can't spawn with empty \"path\"") unless defined $path; + + FORK: { my $pid= fork(); @@ -339,19 +339,6 @@ sub mtr_kill_leftovers () { mtr_report("Killing Possible Leftover Processes"); mtr_debug("mtr_kill_leftovers(): started."); - mkpath("$::opt_vardir/log"); # Needed for mysqladmin log - - # Stop or kill Instance Manager and all its children. If we failed to do - # that, we can only abort -- there is nothing left to do. - - mtr_error("Failed to stop Instance Manager.") - unless mtr_im_stop($::instance_manager); - - # Start shutdown of masters and slaves. Don't touch IM-managed mysqld - # instances -- they should be stopped by mtr_im_stop(). - - mtr_debug("Shutting down mysqld-instances..."); - my @kill_pids; my %admin_pids; @@ -377,40 +364,41 @@ sub mtr_kill_leftovers () { $srv->{'pid'}= 0; # Assume we are done with it } - # Start shutdown of clusters. - - mtr_debug("Shutting down cluster..."); - - foreach my $cluster (@{$::clusters}) + if ( ! $::opt_skip_ndbcluster ) { - mtr_debug(" - cluster " . - "(pid: $cluster->{pid}; " . - "pid file: '$cluster->{path_pid})"); + # Start shutdown of clusters. + mtr_debug("Shutting down cluster..."); - my $pid= mtr_ndbmgm_start($cluster, "shutdown"); - - # Save the pid of the ndb_mgm process - $admin_pids{$pid}= 1; - - push(@kill_pids,{ - pid => $cluster->{'pid'}, - pidfile => $cluster->{'path_pid'} - }); + foreach my $cluster (@{$::clusters}) + { + mtr_debug(" - cluster " . + "(pid: $cluster->{pid}; " . + "pid file: '$cluster->{path_pid})"); - $cluster->{'pid'}= 0; # Assume we are done with it + my $pid= mtr_ndbmgm_start($cluster, "shutdown"); - - foreach my $ndbd (@{$cluster->{'ndbds'}}) - { - mtr_debug(" - ndbd " . - "(pid: $ndbd->{pid}; " . - "pid file: '$ndbd->{path_pid})"); + # Save the pid of the ndb_mgm process + $admin_pids{$pid}= 1; push(@kill_pids,{ - pid => $ndbd->{'pid'}, - pidfile => $ndbd->{'path_pid'}, + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} }); - $ndbd->{'pid'}= 0; # Assume we are done with it + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + mtr_debug(" - ndbd " . + "(pid: $ndbd->{pid}; " . + "pid file: '$ndbd->{path_pid})"); + + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } } } diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 6e3796133f2..ec1bed9671b 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -53,13 +53,6 @@ sub mtr_show_failed_diff ($) { { $result_file= $eval_file; } - elsif ( $::opt_result_ext and - ( $::opt_record or -f "$result_file$::opt_result_ext" )) - { - # If we have an special externsion for result files we use it if we are - # recording or a result file with that extension exists. - $result_file= "$result_file$::opt_result_ext"; - } my $diffopts= $::opt_udiff ? "-u" : "-c"; @@ -151,9 +144,11 @@ sub mtr_report_test_failed ($) { print "[ fail ]\n"; } - # FIXME Instead of this test, and meaningless error message in 'else' - # we should write out into $::path_timefile when the error occurs. - if ( -f $::path_timefile ) + if ( $tinfo->{'comment'} ) + { + print "\nERROR: $tinfo->{'comment'}\n"; + } + elsif ( -f $::path_timefile ) { print "\nErrors are (from $::path_timefile) :\n"; print mtr_fromfile($::path_timefile); # FIXME print_file() instead @@ -177,7 +172,7 @@ sub mtr_report_stats ($) { my $tot_failed= 0; my $tot_tests= 0; my $tot_restarts= 0; - my $found_problems= 0; # Some warnings are errors... + my $found_problems= 0; # Some warnings in the logfiles are errors... foreach my $tinfo (@$tests) { @@ -288,6 +283,7 @@ sub mtr_report_stats ($) { print "\n"; + # Print a list of testcases that failed if ( $tot_failed != 0 ) { my $test_mode= join(" ", @::glob_test_mode) || "default"; @@ -301,7 +297,30 @@ sub mtr_report_stats ($) { } } print "\n"; + + } + + # Print a list of check_testcases that failed(if any) + if ( $::opt_check_testcases ) + { + my @check_testcases= (); + + foreach my $tinfo (@$tests) + { + if ( defined $tinfo->{'check_testcase_failed'} ) + { + push(@check_testcases, $tinfo->{'name'}); + } + } + + if ( @check_testcases ) + { + print "Check of testcase failed for: "; + print join(" ", @check_testcases); + print "\n\n"; + } } + if ( $tot_failed != 0 || $found_problems) { mtr_error("there where failing test cases"); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index e5ed8a99304..0c46bbeac79 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1,30 +1,24 @@ #!/usr/bin/perl # -*- cperl -*- -# This is a transformation of the "mysql-test-run" Bourne shell script -# to Perl. There are reasons this rewrite is not the prettiest Perl -# you have seen # -# - The original script is huge and for most part uncommented, -# not even a usage description of the flags. +############################################################################## +# +# mysql-test-run.pl +# +# Tool used for executing a suite of .test file # -# - There has been an attempt to write a replacement in C for the -# original Bourne shell script. It was kind of working but lacked -# lot of functionality to really be a replacement. Not to redo -# that mistake and catch all the obscure features of the original -# script, the rewrite in Perl is more close to the original script -# meaning it also share some of the ugly parts as well. +# See the "MySQL Test framework manual" for more information +# http://dev.mysql.com/doc/mysqltest/en/index.html # -# - The original intention was that this script was to be a prototype -# to be the base for a new C version with full functionality. Since -# then it was decided that the Perl version should replace the -# Bourne shell version, but the Perl style still reflects the wish -# to make the Perl to C step easy. +# Please keep the test framework tools identical in all versions! # -# Some coding style from the original intent has been kept +############################################################################## +# +# Coding style directions for this perl script # # - To make this Perl script easy to alter even for those that not -# code Perl that often, the coding style is as close as possible to +# code Perl that often, keeep the coding style as close as possible to # the C/C++ MySQL coding standard. # # - All lists of arguments to send to commands are Perl lists/arrays, @@ -42,15 +36,6 @@ # the information. This separates the "find information" from the # "do the work" and makes the program more easy to maintain. # -# - At the moment, there are tons of "global" variables that control -# this script, even accessed from the files in "lib/*.pl". This -# will change over time, for now global variables are used instead -# of using %opt, %path and %exe hashes, because I want more -# compile time checking, that hashes would not give me. Once this -# script is debugged, hashes will be used and passed as parameters -# to functions, to more closely mimic how it would be coded in C -# using structs. -# # - The rule when it comes to the logic of this program is # # command_line_setup() - is to handle the logic between flags @@ -66,10 +51,6 @@ # "http://www.plover.com/~mjd/perl/Trace/" and run this script like # "perl -d:Trace mysql-test-run.pl" # -# FIXME Save a PID file from this code as well, to record the process -# id we think it has. In Cygwin, a fork creates one Cygwin process, -# and then the real Win32 process. Cygwin Perl can only kill Cygwin -# processes. And "mysqld --bootstrap ..." doesn't save a PID file. $Devel::Trace::TRACE= 0; # Don't trace boring init stuff @@ -80,12 +61,16 @@ use File::Copy; use Cwd; use Getopt::Long; use Sys::Hostname; -#use Carp; use IO::Socket; use IO::Socket::INET; use Data::Dumper; use strict; -#use diagnostics; +use diagnostics; + +our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl +our $glob_cygwin_perl= ($^O eq "cygwin"); # Cygwin Perl +our $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); +our $glob_netware= ($^O eq "NetWare"); # NetWare require "lib/mtr_cases.pl"; require "lib/mtr_im.pl"; @@ -102,22 +87,6 @@ require "lib/mtr_stress.pl"; $Devel::Trace::TRACE= 1; -# Used by gcov -our @mysqld_src_dirs= - ( - "strings", - "mysys", - "include", - "extra", - "regex", - "isam", - "merge", - "myisam", - "myisammrg", - "heap", - "sql", - ); - ############################################################################## # # Default settings @@ -130,10 +99,7 @@ our @mysqld_src_dirs= # structs. We let each struct be a separate hash. # Misc global variables - -our $glob_win32= 0; # OS and native Win32 executables -our $glob_win32_perl= 0; # ActiveState Win32 Perl -our $glob_cygwin_perl= 0; # Cygwin Perl +our $mysql_version_id; our $glob_mysql_test_dir= undef; our $glob_mysql_bench_dir= undef; our $glob_hostname= undef; @@ -147,42 +113,38 @@ our @glob_test_mode; our $glob_basedir; -# The total result - our $path_charsetsdir; our $path_client_bindir; our $path_language; our $path_timefile; our $path_snapshot; -our $path_slave_load_tmpdir; # What is this?! our $path_mysqltest_log; our $path_current_test_log; our $path_my_basedir; + our $opt_vardir; # A path but set directly on cmd line -our $opt_vardir_trace; # unix formatted opt_vardir for trace files +our $path_vardir_trace; # unix formatted opt_vardir for trace files our $opt_tmpdir; # A path but set directly on cmd line +our $default_vardir; + our $opt_usage; our $opt_suite; -our $opt_netware; - our $opt_script_debug= 0; # Script debugging, enable with --script-debug our $opt_verbose= 0; # Verbose output, enable with --verbose -# Options FIXME not all.... - our $exe_master_mysqld; our $exe_mysql; our $exe_mysqladmin; our $exe_mysqlbinlog; our $exe_mysql_client_test; our $exe_mysqld; -our $exe_mysqlcheck; # Called from test case -our $exe_mysqldump; # Called from test case -our $exe_mysqlslap; # Called from test case -our $exe_mysqlimport; # Called from test case -our $exe_mysqlshow; # Called from test case +our $exe_mysqlcheck; +our $exe_mysqldump; +our $exe_mysqlslap; +our $exe_mysqlimport; +our $exe_mysqlshow; our $exe_mysql_fix_system_tables; our $exe_mysqltest; our $exe_ndbd; @@ -218,6 +180,7 @@ our $opt_fast; our $opt_force; our $opt_reorder= 0; our $opt_enable_disabled; +our $opt_mem; our $opt_gcov; our $opt_gcov_err; @@ -239,7 +202,7 @@ our $opt_gprof_dir; our $opt_gprof_master; our $opt_gprof_slave; -our $master; # Will be struct in C +our $master; our $slave; our $clusters; @@ -253,8 +216,6 @@ our $opt_ndbconnectstring_slave; our $opt_record; our $opt_check_testcases; -our $opt_result_ext; - our $opt_skip; our $opt_skip_rpl; our $max_slave_num= 0; @@ -326,7 +287,7 @@ our $exe_ndb_waiter; our $path_ndb_tools_dir; our $path_ndb_examples_dir; our $exe_ndb_example; -our $file_ndb_testrun_log; +our $path_ndb_testrun_log; our @data_dir_lst; @@ -334,6 +295,9 @@ our $used_binlog_format; our $debug_compiled_binaries; our $glob_tot_real_time= 0; +our %mysqld_variables; + + ###################################################################### # # Function declarations @@ -343,14 +307,14 @@ our $glob_tot_real_time= 0; sub main (); sub initial_setup (); sub command_line_setup (); -sub snapshot_setup (); +sub datadir_setup (); sub executable_setup (); sub environment_setup (); -sub kill_running_server (); +sub kill_running_servers (); sub cleanup_stale_files (); -sub check_ssl_support (); +sub check_ssl_support ($); sub check_running_as_root(); -sub check_ndbcluster_support (); +sub check_ndbcluster_support ($); sub rm_ndbcluster_tables ($); sub ndbcluster_start_install ($); sub ndbcluster_start ($$); @@ -366,8 +330,8 @@ sub run_testcase_stop_servers ($$$); sub run_testcase_start_servers ($); sub run_testcase_check_skip_test($); sub report_failure_and_restart ($); -sub do_before_start_master ($$); -sub do_before_start_slave ($$); +sub do_before_start_master ($); +sub do_before_start_slave ($); sub ndbd_start ($$$); sub ndb_mgmd_start ($); sub mysqld_start ($$$); @@ -388,11 +352,12 @@ sub main () { initial_setup(); command_line_setup(); - executable_setup(); - check_ndbcluster_support(); - check_ssl_support(); - check_debug_support(); + check_ndbcluster_support(\%mysqld_variables); + check_ssl_support(\%mysqld_variables); + check_debug_support(\%mysqld_variables); + + executable_setup(); environment_setup(); signal_setup(); @@ -441,7 +406,6 @@ sub main () { unless $need_ndbcluster; $opt_skip_im= 1 unless $need_im; - snapshot_setup(); initialize_servers(); run_suite($opt_suite, $tests); @@ -463,13 +427,8 @@ sub initial_setup () { $glob_scriptname= basename($0); - $glob_win32_perl= ($^O eq "MSWin32"); - $glob_cygwin_perl= ($^O eq "cygwin"); - $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); - # We require that we are in the "mysql-test" directory # to run mysql-test-run - if (! -f $glob_scriptname) { mtr_error("Can't find the location for the mysql-test-run script\n" . @@ -493,17 +452,44 @@ sub initial_setup () { chomp($glob_mysql_test_dir); } $glob_basedir= dirname($glob_mysql_test_dir); + # Expect mysql-bench to be located adjacent to the source tree, by default $glob_mysql_bench_dir= "$glob_basedir/../mysql-bench" unless defined $glob_mysql_bench_dir; - # needs to be same length to test logging (FIXME what???) - $path_slave_load_tmpdir= "../../var/tmp"; - $path_my_basedir= $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; $glob_timers= mtr_init_timers(); + + # + # Find the mysqld executable to be able to find the mysqld version + # number as early as possible + # + + # Look for the path where to find the client binaries + $path_client_bindir= mtr_path_exists("$glob_basedir/client/release", + "$glob_basedir/client/debug", + "$glob_basedir/client", + "$glob_basedir/client_release", + "$glob_basedir/client_debug", + "$glob_basedir/bin"); + + # Look for the mysqld executable + $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld", + "$path_client_bindir/mysqld-max-nt", + "$path_client_bindir/mysqld-max", + "$path_client_bindir/mysqld-nt", + "$path_client_bindir/mysqld", + "$path_client_bindir/mysqld-debug", + "$path_client_bindir/mysqld-max", + "$glob_basedir/libexec/mysqld", + "$glob_basedir/sql/release/mysqld", + "$glob_basedir/sql/debug/mysqld"); + + # Use the mysqld found above to find out what features are available + collect_mysqld_features(); + } @@ -661,12 +647,12 @@ sub command_line_setup () { 'tmpdir=s' => \$opt_tmpdir, 'vardir=s' => \$opt_vardir, 'benchdir=s' => \$glob_mysql_bench_dir, + 'mem' => \$opt_mem, # Misc 'comment=s' => \$opt_comment, 'debug' => \$opt_debug, 'fast' => \$opt_fast, - 'netware' => \$opt_netware, 'reorder' => \$opt_reorder, 'enable-disabled' => \$opt_enable_disabled, 'script-debug' => \$opt_script_debug, @@ -722,7 +708,6 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Find out type of logging that are being used # -------------------------------------------------------------------------- - # NOTE if the default binlog format is changed, this has to be changed $used_binlog_format= "stmt"; foreach my $arg ( @opt_extra_mysqld_opt ) @@ -735,16 +720,53 @@ sub command_line_setup () { mtr_report("Using binlog format '$used_binlog_format'"); # -------------------------------------------------------------------------- - # Set the "var/" directory, as it is the base for everything else + # Check if we should speed up tests by trying to run on tmpfs # -------------------------------------------------------------------------- + if ( $opt_mem ) + { + mtr_error("Can't use --mem and --vardir at the same time ") + if $opt_vardir; + mtr_error("Can't use --mem and --tmpdir at the same time ") + if $opt_tmpdir; + + # Use /dev/shm as the preferred location for vardir and + # thus implicitly also tmpdir. Add other locations to list + my @tmpfs_locations= ("/dev/shm"); + # One could maybe use "mount" to find tmpfs location(s) + foreach my $fs (@tmpfs_locations) + { + if ( -d $fs ) + { + mtr_report("Using tmpfs in $fs"); + $opt_mem= "$fs/var"; + $opt_mem .= $ENV{'MTR_BUILD_THREAD'} if $ENV{'MTR_BUILD_THREAD'}; + last; + } + } + } + # -------------------------------------------------------------------------- + # Set the "var/" directory, as it is the base for everything else + # -------------------------------------------------------------------------- + $default_vardir= "$glob_mysql_test_dir/var"; if ( ! $opt_vardir ) { - $opt_vardir= "$glob_mysql_test_dir/var"; + $opt_vardir= $default_vardir; + } + elsif ( $mysql_version_id < 50000 and + $opt_vardir ne $default_vardir ) + { + # Version 4.1 and --vardir was specified + # Only supported as a symlink from var/ + # by setting up $opt_mem that symlink will be created + $opt_mem= $opt_vardir; + $opt_vardir= $default_vardir; + mtr_report("Using 4.1 vardir trick"); } - $opt_vardir_trace= $opt_vardir; + + $path_vardir_trace= $opt_vardir; # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/... - $opt_vardir_trace=~ s/^\w://; + $path_vardir_trace=~ s/^\w://; # We make the path absolute, as the server will do a chdir() before usage unless ( $opt_vardir =~ m,^/, or @@ -755,31 +777,46 @@ sub command_line_setup () { } # -------------------------------------------------------------------------- - # If not set, set these to defaults + # Set tmpdir # -------------------------------------------------------------------------- - $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any # -------------------------------------------------------------------------- - # Do sanity checks of command line arguments + # Set socket # -------------------------------------------------------------------------- - - if ( ! $opt_socket ) - { # FIXME set default before reading options? -# $opt_socket= '@MYSQL_UNIX_ADDR@'; - $opt_socket= "/tmp/mysql.sock"; # FIXME + if (!$opt_socket) + { + $opt_socket= $mysqld_variables{'socket'}; } # -------------------------------------------------------------------------- - # Look at the command line options and set script flags + # Check im suport # -------------------------------------------------------------------------- + if ( $mysql_version_id < 50000 ) + { + # Instance manager is not supported until 5.0 + $opt_skip_im= 1; + + } + + if ( $glob_win32 ) + { + mtr_report("Disable Instance manager - not supported on Windows"); + $opt_skip_im= 1; + } + # -------------------------------------------------------------------------- + # Record flag + # -------------------------------------------------------------------------- if ( $opt_record and ! @opt_cases ) { mtr_error("Will not run in record mode without a specific test case"); } + # -------------------------------------------------------------------------- + # Embedded server flag + # -------------------------------------------------------------------------- if ( $opt_embedded_server ) { $glob_use_embedded_server= 1; @@ -794,11 +831,18 @@ sub command_line_setup () { } } + + # -------------------------------------------------------------------------- + # ps protcol flag + # -------------------------------------------------------------------------- if ( $opt_ps_protocol ) { push(@glob_test_mode, "ps-protocol"); } + # -------------------------------------------------------------------------- + # Ndb cluster flags + # -------------------------------------------------------------------------- if ( $opt_with_ndbcluster and $opt_skip_ndbcluster) { mtr_error("Can't specify both --with-ndbcluster and --skip-ndbcluster"); @@ -834,22 +878,33 @@ sub command_line_setup () { $opt_ndbconnectstring_slave= "host=localhost:$opt_ndbcluster_port_slave"; } + # -------------------------------------------------------------------------- + # Bench flags + # -------------------------------------------------------------------------- if ( $opt_small_bench ) { $opt_bench= 1; } + # -------------------------------------------------------------------------- + # Sleep flag + # -------------------------------------------------------------------------- if ( $opt_sleep ) { $opt_sleep_time_after_restart= $opt_sleep; } + # -------------------------------------------------------------------------- + # Gcov flag + # -------------------------------------------------------------------------- if ( $opt_gcov and ! $opt_source_dist ) { mtr_error("Coverage test needs the source - please use source dist"); } + # -------------------------------------------------------------------------- # Check debug related options + # -------------------------------------------------------------------------- if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd || $opt_manual_gdb || $opt_manual_ddd || $opt_manual_debug || $opt_debugger || $opt_client_debugger ) @@ -864,13 +919,15 @@ sub command_line_setup () { } } - # Check IM arguments - if ( $glob_win32 ) - { - mtr_report("Disable Instance manager - not supported on Windows"); - $opt_skip_im= 1; - } + # -------------------------------------------------------------------------- + # Check if special exe was selected for master or slave + # -------------------------------------------------------------------------- + $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; + $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; + + # -------------------------------------------------------------------------- # Check valgrind arguments + # -------------------------------------------------------------------------- if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options) { mtr_report("Turning on valgrind for all executables"); @@ -1120,11 +1177,12 @@ sub command_line_setup () { $path_timefile= "$opt_vardir/log/mysqltest-time"; $path_mysqltest_log= "$opt_vardir/log/mysqltest.log"; $path_current_test_log= "$opt_vardir/log/current_test"; + $path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; $path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/"; } -sub snapshot_setup () { +sub datadir_setup () { # Make a list of all data_dirs @data_dir_lst = ( @@ -1152,6 +1210,87 @@ sub snapshot_setup () { # ############################################################################## + +sub collect_mysqld_features () { + # + # Execute "mysqld --no-defaults --help --verbose", that will + # print out version and a list of all features and settings + # + my $found_variable_list_start= 0; + my $spec_file= "$glob_mysql_test_dir/mysqld.spec.$$"; + if ( mtr_run($exe_mysqld, + ["--no-defaults", + "--verbose", + "--help"], + "", "$spec_file", "$spec_file", "") != 0 ) + { + mtr_error("Failed to get version and list of features from %s", + $exe_mysqld); + } + + my $F= IO::File->new($spec_file) or + mtr_error("can't open file \"$spec_file\": $!"); + + while ( my $line= <$F> ) + { + # First look for version + if ( !$mysql_version_id ) + { + # Look for version + my $exe_name= basename($exe_mysqld); + mtr_verbose("exe_name: $exe_name"); + if ( $line =~ /^\S*$exe_name\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) + { + #print "Major: $1 Minor: $2 Build: $3\n"; + $mysql_version_id= $1*10000 + $2*100 + $3; + #print "mysql_version_id: $mysql_version_id\n"; + mtr_report("MySQL Version $1.$2.$3"); + } + } + else + { + if (!$found_variable_list_start) + { + # Look for start of variables list + if ( $line =~ /[\-]+\s[\-]+/ ) + { + $found_variable_list_start= 1; + } + } + else + { + # Put variables into hash + if ( $line =~ /^([\S]+)[ \t]+(.*)$/ ) + { + # print "$1=$2\n"; + $mysqld_variables{$1}= $2; + } + else + { + # The variable list is ended with a blank line + if ( $line =~ /^[\s]*$/ ) + { + last; + } + else + { + # Send out a warning, we should fix the variables that has no + # space between variable name and it's value + # or should it be fixed width column parsing? It does not + # look like that in function my_print_variables in my_getopt.c + mtr_warning("Could not parse variable list line : $line"); + } + } + } + } + } + unlink($spec_file); + mtr_error("Could not find version of MySQL") unless $mysql_version_id; + mtr_error("Could not find variabes list") unless $found_variable_list_start; + +} + + sub executable_setup () { # @@ -1169,161 +1308,124 @@ sub executable_setup () { } } - if ( $opt_source_dist ) + # Look for language files and charsetsdir, use same share + my $path_share= mtr_path_exists("$glob_basedir/share", + "$glob_basedir/sql/share", + "$glob_basedir/share/mysql", + "$glob_basedir/share"); + + $path_language= mtr_path_exists("$path_share/english"); + $path_charsetsdir= mtr_path_exists("$path_share/charsets"); + + # Look for my_print_defaults + $exe_my_print_defaults= + mtr_exe_exists("$path_client_bindir/my_print_defaults", + "$glob_basedir/extra/my_print_defaults", + "$glob_basedir/extra/release/my_print_defaults", + "$glob_basedir/extra/debug/my_print_defaults"); + + # Look for perror + $exe_perror= mtr_exe_exists("$glob_basedir/extra/perror", + "$path_client_bindir/perror", + "$glob_basedir/extra/release/perror", + "$glob_basedir/extra/debug/perror"); + + + if ( ! $opt_skip_im ) { - if ( $glob_win32 ) - { - $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", - "$glob_basedir/client_debug", - "$glob_basedir/bin", - # New CMake locations. - "$glob_basedir/client/release", - "$glob_basedir/client/debug"); - $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-max-nt", - "$path_client_bindir/mysqld-max", - "$path_client_bindir/mysqld-nt", - "$path_client_bindir/mysqld", - "$path_client_bindir/mysqld-max", - "$path_client_bindir/mysqld-debug", - "$glob_basedir/sql/release/mysqld", - "$glob_basedir/sql/debug/mysqld"); - $path_language= mtr_path_exists("$glob_basedir/share/english/", - "$glob_basedir/sql/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets", - "$glob_basedir/sql/share/charsets"); - $exe_my_print_defaults= - mtr_exe_exists("$path_client_bindir/my_print_defaults", - "$glob_basedir/extra/release/my_print_defaults", - "$glob_basedir/extra/debug/my_print_defaults"); - $exe_perror= - mtr_exe_exists("$path_client_bindir/perror", - "$glob_basedir/extra/release/perror", - "$glob_basedir/extra/debug/perror"); - } - else - { - $path_client_bindir= mtr_path_exists("$glob_basedir/client"); - $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld"); - $exe_mysqlslap= mtr_exe_exists ("$path_client_bindir/mysqlslap"); - $path_language= mtr_path_exists("$glob_basedir/sql/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/sql/share/charsets"); - - $exe_im= mtr_exe_exists( - "$glob_basedir/server-tools/instance-manager/mysqlmanager"); - $exe_my_print_defaults= - mtr_exe_exists("$glob_basedir/extra/my_print_defaults"); - $exe_perror= - mtr_exe_exists("$glob_basedir/extra/perror"); - } + # Look for instance manager binary - mysqlmanager + $exe_im= + mtr_exe_exists( + "$glob_basedir/server-tools/instance-manager/mysqlmanager", + "$glob_basedir/libexec/mysqlmanager"); + } + else + { + $exe_im= "not_available"; + } - if ( $glob_use_embedded_server ) - { - my $path_examples= "$glob_basedir/libmysqld/examples"; - $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest_embedded"); - $exe_mysql_client_test= - mtr_exe_exists("$path_examples/mysql_client_test_embedded", - "/usr/bin/false"); - } - else - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test", - "$glob_basedir/tests/release/mysql_client_test", - "$glob_basedir/tests/debug/mysql_client_test", - "$path_client_bindir/mysql_client_test", - "/usr/bin/false"); - } - $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); - $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); - $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); - $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); - $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); - $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + # Look for the client binaries + $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); + $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); + $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); + $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); + $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); + $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); + $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + if ( $mysql_version_id >= 50100 ) + { + $exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap"); + } + + if ( ! $glob_win32 ) + { + # Look for mysql_fix_system_table script $exe_mysql_fix_system_tables= mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", - "/usr/bin/false"); - $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/storage/ndb/tools"); - $path_ndb_examples_dir= mtr_path_exists("$glob_basedir/storage/ndb/ndbapi-examples"); - $exe_ndb_example= mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); - $exe_ndb_mgm= "$glob_basedir/storage/ndb/src/mgmclient/ndb_mgm"; - $exe_ndb_waiter= "$glob_basedir/storage/ndb/tools/ndb_waiter"; - $exe_ndbd= "$glob_basedir/storage/ndb/src/kernel/ndbd"; - $exe_ndb_mgmd= "$glob_basedir/storage/ndb/src/mgmsrv/ndb_mgmd"; - $lib_udf_example= - mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so", - "$glob_basedir/sql/release/udf_example.dll", - "$glob_basedir/sql/debug/udf_example.dll"); + "$path_client_bindir/mysql_fix_privilege_tables"); + } + + if ( ! $opt_skip_ndbcluster) + { + # Look for ndb tols and binaries + my $ndb_path= mtr_path_exists("$glob_basedir/ndb", + "$glob_basedir/storage/ndb"); + + $path_ndb_tools_dir= mtr_path_exists("$ndb_path/tools", + "$glob_basedir/bin"); + $exe_ndb_mgm= + mtr_exe_exists("$ndb_path/src/mgmclient/ndb_mgm", + "$glob_basedir/bin/ndb_mgm"); + $exe_ndb_mgmd= + mtr_exe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", + "$glob_basedir/bin/ndb_mgmd"); + $exe_ndb_waiter= + mtr_exe_exists("$ndb_path/tools/ndb_waiter", + "$glob_basedir/bin/ndb_waiter"); + $exe_ndbd= + mtr_exe_exists("$ndb_path/src/kernel/ndbd", + "$glob_basedir/bin/ndbd"); + + $path_ndb_examples_dir= + mtr_path_exists("$ndb_path/ndbapi-examples", + "$ndb_path/examples"); + $exe_ndb_example= + mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); + } + + # Look for the udf_example library + $lib_udf_example= + mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so", + "$glob_basedir/sql/release/udf_example.dll", + "$glob_basedir/sql/debug/udf_example.dll"); + + # Look for mysqltest executable + if ( $glob_use_embedded_server ) + { + $exe_mysqltest= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysqltest_embedded", + "$path_client_bindir/mysqltest_embedded"); } else { - $path_client_bindir= mtr_path_exists("$glob_basedir/bin"); - $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); - $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); - $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); - $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); - $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); - $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); - $exe_mysql_fix_system_tables= - mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", - "$glob_basedir/scripts/mysql_fix_privilege_tables", - "/usr/bin/false"); - $exe_my_print_defaults= - mtr_exe_exists("$path_client_bindir/my_print_defaults"); - $exe_perror= - mtr_exe_exists("$path_client_bindir/perror"); - - $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", - "$glob_basedir/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/share/mysql/charsets", - "$glob_basedir/share/charsets"); - - if ( $glob_win32 ) - { - $exe_mysqld= mtr_exe_exists ("$glob_basedir/bin/mysqld-nt", - "$glob_basedir/bin/mysqld", - "$glob_basedir/bin/mysqld-debug",); - } - else - { - $exe_mysqld= mtr_exe_exists ("$glob_basedir/libexec/mysqld", - "$glob_basedir/bin/mysqld"); - $exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap"); - } - $exe_im= mtr_exe_exists("$glob_basedir/libexec/mysqlmanager", - "$glob_basedir/bin/mysqlmanager"); - if ( $glob_use_embedded_server ) - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest_embedded"); - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test_embedded", - "$path_client_bindir/mysql_client_test_embedded", - "/usr/bin/false"); - } - else - { $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); - $exe_mysql_client_test= - mtr_exe_exists("$path_client_bindir/mysql_client_test", - "$glob_basedir/tests/release/mysql_client_test", - "$glob_basedir/tests/debug/mysql_client_test", - "/usr/bin/false"); # FIXME temporary - } - $path_ndb_tools_dir= "$glob_basedir/bin"; - $path_ndb_examples_dir= "$glob_basedir/ndbapi-examples"; - $exe_ndb_mgm= "$glob_basedir/bin/ndb_mgm"; - $exe_ndb_waiter= "$glob_basedir/bin/ndb_waiter"; - $exe_ndbd= "$glob_basedir/bin/ndbd"; - $exe_ndb_mgmd= "$glob_basedir/bin/ndb_mgmd"; - } - $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; - $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; + } - $file_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; + # Look for mysql_client_test executable + if ( $glob_use_embedded_server ) + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); + } + else + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/tests/mysql_client_test", + "$glob_basedir/tests/release/mysql_client_test", + "$glob_basedir/tests/debug/mysql_client_test"); + } } @@ -1394,11 +1496,13 @@ sub environment_setup () { } $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths, - split(':', $ENV{'LD_LIBRARY_PATH'})); + $ENV{'LD_LIBRARY_PATHS'} ? + split(':', $ENV{'LD_LIBRARY_PATH'}) : ()); mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}"); $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths, - split(':', $ENV{'DYLD_LIBRARY_PATH'})); + $ENV{'DYLD_LIBRARY_PATH'} ? + split(':', $ENV{'DYLD_LIBRARY_PATH'}) : ()); mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}"); @@ -1422,30 +1526,32 @@ sub environment_setup () { $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'}; $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'}; $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'}; -# $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME - $ENV{'MYSQL_TCP_PORT'}= 3306; + $ENV{'MYSQL_TCP_PORT'}= $mysqld_variables{'port'}; $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set # ---------------------------------------------------- # Setup env for NDB # ---------------------------------------------------- - $ENV{'NDB_MGM'}= $exe_ndb_mgm; + if ( ! $opt_skip_ndbcluster ) + { + $ENV{'NDB_MGM'}= $exe_ndb_mgm; - $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; - $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; + $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; + $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; - $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; + $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; - $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; - $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; - $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; - $ENV{'NDB_TOOLS_OUTPUT'}= $file_ndb_testrun_log; - $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; + $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; + $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; + $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; - $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; - $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; - $ENV{'NDB_EXAMPLES_OUTPUT'}= $file_ndb_testrun_log; + $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; + $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; + $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; + } # ---------------------------------------------------- # Setup env for IM @@ -1475,7 +1581,7 @@ sub environment_setup () { if ( $opt_debug ) { $cmdline_mysqlcheck .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlcheck.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqlcheck.trace"; } $ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck; @@ -1488,9 +1594,9 @@ sub environment_setup () { if ( $opt_debug ) { $cmdline_mysqldump .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqldump-master.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-master.trace"; $cmdline_mysqldumpslave .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqldump-slave.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-slave.trace"; } $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; $ENV{'MYSQL_DUMP_SLAVE'}= $cmdline_mysqldumpslave; @@ -1499,7 +1605,7 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env so childs can execute mysqlslap # ---------------------------------------------------- - unless ( $glob_win32 ) + if ( $exe_mysqlslap ) { my $cmdline_mysqlslap= "$exe_mysqlslap -uroot " . @@ -1510,7 +1616,7 @@ sub environment_setup () { if ( $opt_debug ) { $cmdline_mysqlslap .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlslap.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; } $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; } @@ -1526,7 +1632,7 @@ sub environment_setup () { if ( $opt_debug ) { $cmdline_mysqlimport .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlimport.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqlimport.trace"; } $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; @@ -1542,7 +1648,7 @@ sub environment_setup () { if ( $opt_debug ) { $cmdline_mysqlshow .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlshow.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqlshow.trace"; } $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; @@ -1551,13 +1657,16 @@ sub environment_setup () { # ---------------------------------------------------- my $cmdline_mysqlbinlog= "$exe_mysqlbinlog" . - " --no-defaults --local-load=$opt_tmpdir" . - " --character-sets-dir=$path_charsetsdir"; + " --no-defaults --local-load=$opt_tmpdir"; + if ( $mysql_version_id >= 50000 ) + { + $cmdline_mysqlbinlog .=" --character-sets-dir=$path_charsetsdir"; + } if ( $opt_debug ) { $cmdline_mysqlbinlog .= - " --debug=d:t:A,$opt_vardir_trace/log/mysqlbinlog.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysqlbinlog.trace"; } $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; @@ -1578,13 +1687,16 @@ sub environment_setup () { my $cmdline_mysql_client_test= "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . "--port=$master->[0]->{'port'} " . - "--vardir=$opt_vardir " . "--socket=$master->[0]->{'path_sock'}"; + if ( $mysql_version_id >= 50000 ) + { + $cmdline_mysql_client_test .=" --vardir=$opt_vardir"; + } if ( $opt_debug ) { $cmdline_mysql_client_test .= - " --debug=d:t:A,$opt_vardir_trace/log/mysql_client_test.trace"; + " --debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace"; } if ( $glob_use_embedded_server ) @@ -1601,7 +1713,8 @@ sub environment_setup () { # Setup env so childs can execute mysql_fix_system_tables # ---------------------------------------------------- my $cmdline_mysql_fix_system_tables= - "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . + "$exe_mysql_fix_system_tables --no-defaults --host=localhost " . + "--user=root --password= " . "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . "--port=$master->[0]->{'port'} " . "--socket=$master->[0]->{'path_sock'}"; @@ -1641,12 +1754,26 @@ sub environment_setup () { print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n"; print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n"; print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n"; - print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; - print "Using NDBCLUSTER_PORT_SLAVE = $ENV{NDBCLUSTER_PORT_SLAVE}\n"; - print "Using IM_PORT = $ENV{IM_PORT}\n"; - print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n"; - print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; + if ( ! $opt_skip_ndbcluster ) + { + print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; + if ( ! $opt_skip_ndbcluster_slave ) + { + print "Using NDBCLUSTER_PORT_SLAVE = $ENV{NDBCLUSTER_PORT_SLAVE}\n"; + } + } + if ( ! $opt_skip_im ) + { + print "Using IM_PORT = $ENV{IM_PORT}\n"; + print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n"; + print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; + } } + + # Create an environment variable to make it possible + # to detect that valgrind is being used from test cases + $ENV{'VALGRIND_TEST'}= $opt_valgrind; + } @@ -1676,7 +1803,7 @@ sub handle_int_signal () { # ############################################################################## -sub kill_running_server () { +sub kill_running_servers () { if ( $opt_fast or $glob_use_embedded_server ) { @@ -1694,28 +1821,48 @@ sub kill_running_server () { # started from this run of the script, this is terminating # leftovers from previous runs. + if ( ! -d $opt_vardir ) + { + # The "var" dir does not exist already + # the processes that mtr_kill_leftovers start will write + # their log files to var/log so it should be created + mkpath("$opt_vardir/log"); + } mtr_kill_leftovers(); } } sub cleanup_stale_files () { + my $created_by_mem_file= "$glob_mysql_test_dir/var/created_by_mem"; + mtr_report("Removing Stale Files"); - if ( $opt_vardir eq "$glob_mysql_test_dir/var" ) + if ( $opt_vardir eq $default_vardir ) { # # Running with "var" in mysql-test dir # - if ( -l "$glob_mysql_test_dir/var" ) + if ( -l $opt_vardir) { - # Some users creates a soft link in mysql-test/var to another area - # - allow it - mtr_report("WARNING: Using the 'mysql-test/var' symlink"); - rmtree("$opt_vardir/log"); - rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port"); - rmtree("$opt_vardir/run"); - rmtree("$opt_vardir/tmp"); + # var is a symlink + if (-f $created_by_mem_file) + { + # Remove the directory which the link points at + rmtree(readlink($opt_vardir)); + # Remove the entire "var" dir + rmtree("$opt_vardir/"); + } + else + { + # Some users creates a soft link in mysql-test/var to another area + # - allow it + mtr_report("WARNING: Using the 'mysql-test/var' symlink"); + rmtree("$opt_vardir/log"); + rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port"); + rmtree("$opt_vardir/run"); + rmtree("$opt_vardir/tmp"); + } } else { @@ -1731,12 +1878,23 @@ sub cleanup_stale_files () { # Remove the var/ dir in mysql-test dir if any # this could be an old symlink that shouldn't be there - rmtree("$glob_mysql_test_dir/var"); + rmtree($default_vardir); # Remove the "var" dir rmtree("$opt_vardir/"); } + if ( $opt_mem ) + { + # Runinng with var as a link to some "memory" location, normally tmpfs + rmtree($opt_mem); + mkpath($opt_mem); + mtr_report("Creating symlink from $opt_vardir to $opt_mem"); + symlink($opt_mem, $opt_vardir); + # Put a small file to recognize this dir was created by --mem + mtr_tofile($created_by_mem_file, $opt_mem); + } + mkpath("$opt_vardir/log"); mkpath("$opt_vardir/run"); mkpath("$opt_vardir/tmp"); @@ -1797,8 +1955,8 @@ sub check_running_as_root () { } - -sub check_ssl_support () { +sub check_ssl_support ($) { + my $mysqld_variables= shift; if ($opt_skip_ssl || $opt_extern) { @@ -1808,13 +1966,7 @@ sub check_ssl_support () { return; } - # check ssl support by testing using a switch - # that is only available in that case - if ( mtr_run($exe_mysqld, - ["--no-defaults", - "--ssl", - "--help"], - "", "/dev/null", "/dev/null", "") != 0 ) + if ( ! $mysqld_variables->{'ssl'} ) { if ( $opt_ssl) { @@ -1831,17 +1983,12 @@ sub check_ssl_support () { } -sub check_debug_support () { +sub check_debug_support ($) { + my $mysqld_variables= shift; - # check debug support by testing using a switch - # that is only available in that case - if ( mtr_run($exe_mysqld, - ["--no-defaults", - "--debug", - "--help"], - "", "/dev/null", "/dev/null", "") != 0 ) + if ( ! $mysqld_variables->{'debug'} ) { - # mtr_report("Binaries are not debug compiled"); + #mtr_report("Binaries are not debug compiled"); $debug_compiled_binaries= 0; if ( $opt_debug ) @@ -1860,7 +2007,8 @@ sub check_debug_support () { # ############################################################################## -sub check_ndbcluster_support () { +sub check_ndbcluster_support ($) { + my $mysqld_variables= shift; if ($opt_skip_ndbcluster) { @@ -1869,13 +2017,7 @@ sub check_ndbcluster_support () { return; } - # check ndbcluster support by runnning mysqld using a switch - # that is only available in that case - if ( mtr_run($exe_mysqld, - ["--no-defaults", - "--ndb-use-exact-count", - "--help"], - "", "/dev/null", "/dev/null", "") != 0 ) + if ( ! $mysqld_variables->{'ndb-connectstring'} ) { mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster"); $opt_skip_ndbcluster= 1; @@ -1884,6 +2026,14 @@ sub check_ndbcluster_support () { } $opt_ndbcluster_supported= 1; mtr_report("Using ndbcluster when necessary, mysqld supports it"); + + if ( $mysql_version_id < 50100 ) + { + # Slave cluster is not supported until 5.1 + $opt_skip_ndbcluster_slave= 1; + + } + return; } @@ -1914,11 +2064,22 @@ sub ndbcluster_start_install ($) { if (!$opt_bench) { # Use a smaller configuration - $ndb_no_ord=32; - $ndb_con_op=5000; - $ndb_dmem="20M"; - $ndb_imem="1M"; - $ndb_pbmem="4M"; + if ( $mysql_version_id < 50100 ) + { + # 4.1 and 5.0 is using a "larger" --small configuration + $ndb_no_ord=128; + $ndb_con_op=10000; + $ndb_dmem="40M"; + $ndb_imem="12M"; + } + else + { + $ndb_no_ord=32; + $ndb_con_op=5000; + $ndb_dmem="20M"; + $ndb_imem="1M"; + $ndb_pbmem="4M"; + } } my $config_file_template= "ndb/ndb_config_${nodes}_node.ini"; @@ -1941,6 +2102,11 @@ sub ndbcluster_start_install ($) { s/CHOOSE_HOSTNAME_.*/$ndb_host/; s/CHOOSE_FILESYSTEM/$cluster->{'data_dir'}/; s/CHOOSE_PORT_MGM/$cluster->{'port'}/; + if ( $mysql_version_id < 50000 ) + { + my $base_port= $cluster->{'port'} + 1; + s/CHOOSE_PORT_TRANSPORTER/$base_port/; + } s/CHOOSE_DiskPageBufferMemory/$ndb_pbmem/; print OUT "$_ \n"; @@ -2062,7 +2228,10 @@ sub ndbd_start ($$$) { mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--core"); mtr_add_arg($args, "--ndb-connectstring=%s", "$cluster->{'connect_string'}"); - mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); + if ( $mysql_version_id >= 50000) + { + mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); + } mtr_add_arg($args, "--nodaemon"); mtr_add_arg($args, "$extra_args"); @@ -2163,8 +2332,6 @@ sub run_benchmarks ($) { chdir($glob_mysql_bench_dir) or mtr_error("Couldn't chdir to '$glob_mysql_bench_dir': $!"); - # FIXME write shorter.... - if ( ! $benchmark ) { mtr_add_arg($args, "--log"); @@ -2196,9 +2363,6 @@ sub run_benchmarks ($) { # ############################################################################## -# FIXME how to specify several suites to run? Comma separated list? - - sub run_suite () { my ($suite, $tests)= @_; @@ -2255,11 +2419,14 @@ sub run_suite () { ############################################################################## sub initialize_servers () { + + datadir_setup(); + if ( ! $glob_use_running_server ) { - kill_running_server(); + kill_running_servers(); - unless ( $opt_start_dirty ) + if ( ! $opt_start_dirty ) { cleanup_stale_files(); mysql_install_db(); @@ -2293,7 +2460,8 @@ sub mysql_install_db () { my $cluster_started_ok= 1; # Assume it can be started if (ndbcluster_start_install($clusters->[0]) || - $max_slave_num && ndbcluster_start_install($clusters->[1])) + ($max_slave_num && !$opt_skip_ndbcluster_slave && + ndbcluster_start_install($clusters->[1]))) { mtr_warning("Failed to start install of cluster"); $cluster_started_ok= 0; @@ -2396,10 +2564,10 @@ sub install_db ($$) { if ( $opt_debug ) { mtr_add_arg($args, "--debug=d:t:i:A,%s/log/bootstrap_%s.trace", - $opt_vardir_trace, $type); + $path_vardir_trace, $type); } - if ( ! $opt_netware ) + if ( ! $glob_netware ) { mtr_add_arg($args, "--language=%s", $path_language); mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); @@ -2492,9 +2660,15 @@ skip-innodb skip-ndbcluster EOF ; - + if ( $mysql_version_id < 50100 ) + { + print OUT "skip-bdb\n"; + } print OUT "nonguarded\n" if $instance->{'nonguarded'}; - print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; + if ( $mysql_version_id >= 50100 ) + { + print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; + } print OUT "\n"; } @@ -2553,21 +2727,24 @@ sub run_testcase_check_skip_test($) return 1; } - # If test needs cluster, check that master installed ok - if ( $tinfo->{'ndb_test'} and !$clusters->[0]->{'installed_ok'} ) + if ($tinfo->{'ndb_test'}) { - mtr_report_test_name($tinfo); - mtr_report_test_failed($tinfo); - return 1; - } + foreach my $cluster (@{$clusters}) + { + last if ($opt_skip_ndbcluster_slave and + $cluster->{'name'} eq 'Slave'); - # If test needs slave cluster, check that it installed ok - if ( $tinfo->{'ndb_test'} and $tinfo->{'slave_num'} and - !$clusters->[1]->{'installed_ok'} ) - { - mtr_report_test_name($tinfo); - mtr_report_test_failed($tinfo); - return 1; + # If test needs this cluster, check it was installed ok + if ( !$cluster->{'installed_ok'} ) + { + mtr_tofile($path_timefile, + "Test marked as failed because $cluster->{'name'} " . + "was not installed ok!"); + mtr_report_test_name($tinfo); + mtr_report_test_failed($tinfo); + return 1; + } + } } return 0; @@ -2579,28 +2756,40 @@ sub do_before_run_mysqltest($) my $tinfo= shift; my $tname= $tinfo->{'name'}; - # Remove old reject file - if ( $opt_suite eq "main" ) - { - unlink("r/$tname.reject"); - } - else + # Remove old files produced by mysqltest + my $result_dir= "r"; + if ( $opt_suite ne "main" ) { - unlink("suite/$opt_suite/r/$tname.reject"); + $result_dir= "suite/$opt_suite/r"; } + unlink("$result_dir/$tname.reject"); + unlink("$result_dir/$tname.progress"); + unlink("$result_dir/$tname.log"); + unlink("$result_dir/$tname.warnings"); - -# MASV cleanup... mtr_tonewfile($path_current_test_log,"$tname\n"); # Always tell where we are # output current test to ndbcluster log file to enable diagnostics - mtr_tofile($file_ndb_testrun_log,"CURRENT TEST $tname\n"); + mtr_tofile($path_ndb_testrun_log,"CURRENT TEST $tname\n"); mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); if ( $master->[1]->{'pid'} ) { mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); } + + if ( $mysql_version_id < 50000 ) + { + # Set envirnoment variable NDB_STATUS_OK to 1 + # if script decided to run mysqltest cluster _is_ installed ok + $ENV{'NDB_STATUS_OK'} = "1"; + } + elsif ( $mysql_version_id < 50100 ) + { + # Set envirnoment variable NDB_STATUS_OK to YES + # if script decided to run mysqltest cluster _is_ installed ok + $ENV{'NDB_STATUS_OK'} = "YES"; + } } sub do_after_run_mysqltest($) @@ -2608,12 +2797,16 @@ sub do_after_run_mysqltest($) my $tinfo= shift; my $tname= $tinfo->{'name'}; - #MASV cleanup - # Save info from this testcase run to mysqltest.log - my $testcase_log= mtr_fromfile($path_timefile) if -f $path_timefile; - mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); - mtr_tofile($path_mysqltest_log, $testcase_log); - } + mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); + + # Save info from this testcase run to mysqltest.log + mtr_appendfile_to_file($path_timefile, $path_mysqltest_log) + if -f $path_timefile; + + # Remove the file that mysqltest writes info to + unlink($path_timefile); + +} ############################################################################## @@ -2640,12 +2833,28 @@ sub run_testcase ($) { if ($master_restart or $slave_restart) { + # Can't restart a running server that may be in use + if ( $glob_use_running_server ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Can't restart a running server"; + + mtr_report_test_name($tinfo); + mtr_report_test_skipped($tinfo); + return; + } + run_testcase_stop_servers($tinfo, $master_restart, $slave_restart); } my $died= mtr_record_dead_children(); if ($died or $master_restart or $slave_restart) { - run_testcase_start_servers($tinfo); + if (run_testcase_start_servers($tinfo)) + { + mtr_report_test_name($tinfo); + report_failure_and_restart($tinfo); + return 1; + } } # ---------------------------------------------------------------------- @@ -2702,13 +2911,10 @@ sub run_testcase ($) { # ---------------------------------------------------------------------- # Stop Instance Manager if we are processing an IM-test case. # ---------------------------------------------------------------------- - - if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' ) + if ( $tinfo->{'component_id'} eq 'im' and + !mtr_im_stop($instance_manager, $tinfo->{'name'}) ) { - unless ( mtr_im_stop($instance_manager, $tinfo->{'name'}) ) - { - mtr_error("Failed to stop Instance Manager.") - } + mtr_error("Failed to stop Instance Manager.") } } @@ -2824,24 +3030,17 @@ sub report_failure_and_restart ($) { ############################################################################## -# The embedded server needs the cleanup so we do some of the start work -# but stop before actually running mysqld or anything. -sub do_before_start_master ($$) { - my $tname= shift; - my $init_script= shift; +sub do_before_start_master ($) { + my ($tinfo)= @_; + + my $tname= $tinfo->{'name'}; + my $init_script= $tinfo->{'master_sh'}; # FIXME what about second master..... - # Remove stale binary logs except for 2 tests which need them FIXME here???? - if ( $tname ne "rpl_crash_binlog_ib_1b" and - $tname ne "rpl_crash_binlog_ib_2b" and - $tname ne "rpl_crash_binlog_ib_3b") + foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) { - # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) - { - unlink($bin); - } + unlink($bin); } # FIXME only remove the ones that are tied to this master @@ -2861,31 +3060,23 @@ sub do_before_start_master ($$) { # mtr_warning("$init_script exited with code $ret"); } } - # for gcov FIXME needed? If so we need more absolute paths - # chdir($glob_basedir); } -sub do_before_start_slave ($$) { - my $tname= shift; - my $init_script= shift; +sub do_before_start_slave ($) { + my ($tinfo)= @_; - # Remove stale binary logs and old master.info files - # except for too tests which need them - if ( $tname ne "rpl_crash_binlog_ib_1b" and - $tname ne "rpl_crash_binlog_ib_2b" and - $tname ne "rpl_crash_binlog_ib_3b" ) + my $tname= $tinfo->{'name'}; + my $init_script= $tinfo->{'master_sh'}; + + foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) { - # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) - { - unlink($bin); - } - # FIXME really master?! - unlink("$slave->[0]->{'path_myddir'}/master.info"); - unlink("$slave->[0]->{'path_myddir'}/relay-log.info"); + unlink($bin); } + unlink("$slave->[0]->{'path_myddir'}/master.info"); + unlink("$slave->[0]->{'path_myddir'}/relay-log.info"); + # Run slave initialization shell script if one exists if ( $init_script ) { @@ -2924,14 +3115,18 @@ sub mysqld_arguments ($$$$$) { $prefix= "--server-arg="; } else { # We can't pass embedded server --no-defaults - mtr_add_arg($args, "%s--no-defaults", $prefix); + mtr_add_arg($args, "--no-defaults"); } mtr_add_arg($args, "%s--console", $prefix); mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); - mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); + } + mtr_add_arg($args, "%s--default-character-set=latin1", $prefix); mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); @@ -2980,7 +3175,10 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $cluster->{'connect_string'}); - mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + if ( $mysql_version_id >= 50100 ) + { + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } } @@ -2998,7 +3196,7 @@ sub mysqld_arguments ($$$$$) { $opt_vardir, $sidx); # FIXME use own dir for binlogs mtr_add_arg($args, "%s--log-slave-updates", $prefix); } - # FIXME option duplicated for slave + mtr_add_arg($args, "%s--log=%s", $prefix, $slave->[$idx]->{'path_mylog'}); mtr_add_arg($args, "%s--master-retry-count=10", $prefix); @@ -3019,8 +3217,9 @@ sub mysqld_arguments ($$$$$) { # Directory where slaves find the dumps generated by "load data" # on the server. The path need to have constant length otherwise # test results will vary, thus a relative path is used. + my $slave_load_path= "../tmp"; mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, - "../tmp"); + $slave_load_path); mtr_add_arg($args, "%s--socket=%s", $prefix, $slave->[$idx]->{'path_sock'}); mtr_add_arg($args, "%s--set-variable=slave_net_timeout=10", $prefix); @@ -3055,7 +3254,10 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $clusters->[$slave->[$idx]->{'cluster'}]->{'connect_string'}); - mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + if ( $mysql_version_id >= 50100 ) + { + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } } # end slave @@ -3064,12 +3266,12 @@ sub mysqld_arguments ($$$$$) { if ( $type eq 'master' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/master%s.trace", - $prefix, $opt_vardir_trace, $sidx); + $prefix, $path_vardir_trace, $sidx); } if ( $type eq 'slave' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/slave%s.trace", - $prefix, $opt_vardir_trace, $sidx); + $prefix, $path_vardir_trace, $sidx); } } @@ -3077,7 +3279,6 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix); mtr_add_arg($args, "%s--sort_buffer=256K", $prefix); mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix); - mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); if ( $opt_ssl_supported ) { @@ -3255,10 +3456,13 @@ sub stop_all_servers () { print "Stopping All Servers\n"; - print "Shutting-down Instance Manager\n"; - unless (mtr_im_stop($instance_manager, "stop_all_servers")) + if ( ! $opt_skip_im ) { - mtr_error("Failed to stop Instance Manager.") + print "Shutting-down Instance Manager\n"; + unless (mtr_im_stop($instance_manager, "stop_all_servers")) + { + mtr_error("Failed to stop Instance Manager.") + } } my %admin_pids; # hash of admin processes that requests shutdown @@ -3333,46 +3537,46 @@ sub run_testcase_need_master_restart($) # We try to find out if we are to restart the master(s) my $do_restart= 0; # Assumes we don't have to - if ( $tinfo->{'master_sh'} ) + if ( $glob_use_embedded_server ) + { + mtr_verbose("Never start or restart for embedded server"); + return $do_restart; + } + elsif ( $tinfo->{'master_sh'} ) { $do_restart= 1; # Always restart if script to run - mtr_verbose("Restart because: Always restart if script to run"); + mtr_verbose("Restart master: Always restart if script to run"); + } + if ( $tinfo->{'force_restart'} ) + { + $do_restart= 1; # Always restart if --force-restart in -opt file + mtr_verbose("Restart master: Restart forced with --force-restart"); } elsif ( ! $opt_skip_ndbcluster and $tinfo->{'ndb_test'} == 0 and $clusters->[0]->{'pid'} != 0 ) { $do_restart= 1; # Restart without cluster - mtr_verbose("Restart because: Test does not need cluster"); + mtr_verbose("Restart master: Test does not need cluster"); } elsif ( ! $opt_skip_ndbcluster and $tinfo->{'ndb_test'} == 1 and $clusters->[0]->{'pid'} == 0 ) { $do_restart= 1; # Restart with cluster - mtr_verbose("Restart because: Test need cluster"); - } - elsif ( $master->[0]->{'running_master_is_special'} and - $master->[0]->{'running_master_is_special'}->{'timezone'} eq - $tinfo->{'timezone'} and - mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, - $tinfo->{'master_opt'}) ) - { - # If running master was started with special settings, but - # the current test requires the same ones, we *don't* restart. - $do_restart= 0; - mtr_verbose("Skip restart: options are equal " . - join(" ", @{$tinfo->{'master_opt'}})); + mtr_verbose("Restart master: Test need cluster"); } - elsif ( $tinfo->{'master_restart'} ) + elsif( $tinfo->{'component_id'} eq 'im' ) { $do_restart= 1; - mtr_verbose("Restart because: master_restart"); + mtr_verbose("Restart master: Always restart for im tests"); } - elsif ( $master->[0]->{'running_master_is_special'} ) + elsif ( $master->[0]->{'running_master_options'} and + $master->[0]->{'running_master_options'}->{'timezone'} ne + $tinfo->{'timezone'}) { $do_restart= 1; - mtr_verbose("Restart because: running_master_is_special"); + mtr_verbose("Restart master: Different timezone"); } # Check that running master was started with same options # as the current test requires @@ -3380,10 +3584,15 @@ sub run_testcase_need_master_restart($) $tinfo->{'master_opt'}) ) { $do_restart= 1; - mtr_verbose("Restart because: running with different options '" . + mtr_verbose("Restart master: running with different options '" . join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); } + elsif( ! $master->[0]->{'pid'} ) + { + $do_restart= 1; + mtr_verbose("Restart master: master is not started"); + } return $do_restart; } @@ -3395,57 +3604,40 @@ sub run_testcase_need_slave_restart($) # We try to find out if we are to restart the slaves my $do_slave_restart= 0; # Assumes we don't have to - # FIXME only restart slave when necessary - $do_slave_restart= 1; - -# if ( ! $slave->[0]->{'pid'} ) -# { -# # mtr_verbose("Slave not started, no need to check slave restart"); -# } -# elsif ( $do_restart ) -# { -# $do_slave_restart= 1; # Always restart if master restart -# mtr_verbose("Restart slave because: Master restart"); -# } -# elsif ( $tinfo->{'slave_sh'} ) -# { -# $do_slave_restart= 1; # Always restart if script to run -# mtr_verbose("Restart slave because: Always restart if script to run"); -# } -# elsif ( ! $opt_skip_ndbcluster_slave and -# $tinfo->{'ndb_test'} == 0 and -# $clusters->[1]->{'pid'} != 0 ) -# { -# $do_slave_restart= 1; # Restart without slave cluster -# mtr_verbose("Restart slave because: Test does not need slave cluster"); -# } -# elsif ( ! $opt_with_ndbcluster_slave and -# $tinfo->{'ndb_test'} == 1 and -# $clusters->[1]->{'pid'} == 0 ) -# { -# $do_slave_restart= 1; # Restart with slave cluster -# mtr_verbose("Restart slave because: Test need slave cluster"); -# } -# elsif ( $tinfo->{'slave_restart'} ) -# { -# $do_slave_restart= 1; -# mtr_verbose("Restart slave because: slave_restart"); -# } -# elsif ( $slave->[0]->{'running_slave_is_special'} ) -# { -# $do_slave_restart= 1; -# mtr_verbose("Restart slave because: running_slave_is_special"); -# } -# # Check that running slave was started with same options -# # as the current test requires -# elsif (! mtr_same_opts($slave->[0]->{'start_opts'}, -# $tinfo->{'slave_opt'}) ) -# { -# $do_slave_restart= 1; -# mtr_verbose("Restart slave because: running with different options '" . -# join(" ", @{$tinfo->{'slave_opt'}}) . "' != '" . -# join(" ", @{$slave->[0]->{'start_opts'}}) . "'" ); -# } + if ( $glob_use_embedded_server ) + { + mtr_verbose("Never start or restart for embedded server"); + return $do_slave_restart; + } + elsif ( $max_slave_num == 0) + { + mtr_verbose("Skip slave restart: No testcase use slaves"); + } + else + { + + # Check if any slave is currently started + my $any_slave_started= 0; + foreach my $mysqld (@{$slave}) + { + if ( $mysqld->{'pid'} ) + { + $any_slave_started= 1; + last; + } + } + + if ($any_slave_started) + { + mtr_verbose("Restart slave: Slave is started, always restart"); + $do_slave_restart= 1; + } + elsif ( $tinfo->{'slave_num'} ) + { + mtr_verbose("Restart slave: Test need slave"); + $do_slave_restart= 1; + } + } return $do_slave_restart; @@ -3464,22 +3656,16 @@ sub run_testcase_need_slave_restart($) sub run_testcase_stop_servers($$$) { my ($tinfo, $do_restart, $do_slave_restart)= @_; - - if ( $glob_use_running_server || $glob_use_embedded_server ) - { - return; - } - my $pid; my %admin_pids; # hash of admin processes that requests shutdown my @kill_pids; # list of processes to shutdown/kill - # Remember if we restarted for this test case + # Remember if we restarted for this test case (count restarts) $tinfo->{'restarted'}= $do_restart; if ( $do_restart ) { - delete $master->[0]->{'running_master_is_special'}; # Forget history + delete $master->[0]->{'running_master_options'}; # Forget history # Start shutdown of all started masters foreach my $mysqld (@{$master}) @@ -3529,7 +3715,7 @@ sub run_testcase_stop_servers($$$) { if ( $do_restart || $do_slave_restart ) { - delete $slave->[0]->{'running_slave_is_special'}; # Forget history + delete $slave->[0]->{'running_slave_options'}; # Forget history # Start shutdown of all started slaves foreach my $mysqld (@{$slave}) @@ -3600,15 +3786,26 @@ sub run_testcase_stop_servers($$$) { } } + +# +# run_testcase_start_servers +# +# Start the servers needed by this test case +# +# RETURN +# 0 OK +# 1 Start failed +# + sub run_testcase_start_servers($) { my $tinfo= shift; - my $tname= $tinfo->{'name'}; - if ( $glob_use_running_server or $glob_use_embedded_server ) - { - return; - } + # ------------------------------------------------------- + # Init variables that can change between server starts + # ------------------------------------------------------- + $ENV{'TZ'}= $tinfo->{'timezone'}; + mtr_verbose("Starting server with timezone: $tinfo->{'timezone'}"); if ( $tinfo->{'component_id'} eq 'mysqld' ) { @@ -3623,7 +3820,7 @@ sub run_testcase_start_servers($) { if ( !$master->[0]->{'pid'} ) { # Master mysqld is not started - do_before_start_master($tname,$tinfo->{'master_sh'}); + do_before_start_master($tinfo); mysqld_start($master->[0],$tinfo->{'master_opt'},[]); @@ -3633,27 +3830,28 @@ sub run_testcase_start_servers($) { { # Test needs cluster, start an extra mysqld connected to cluster - # First wait for first mysql server to have created ndb system tables ok - # FIXME This is a workaround so that only one mysqld creates the tables - if ( ! sleep_until_file_created( - "$master->[0]->{'path_myddir'}/cluster/apply_status.ndb", - $master->[0]->{'start_timeout'}, - $master->[0]->{'pid'})) + if ( $mysql_version_id >= 50100 ) { - mtr_report("Failed to create 'cluster/apply_status' table"); - report_failure_and_restart($tinfo); - return; + # First wait for first mysql server to have created ndb system + # tables ok FIXME This is a workaround so that only one mysqld + # create the tables + if ( ! sleep_until_file_created( + "$master->[0]->{'path_myddir'}/cluster/apply_status.ndb", + $master->[0]->{'start_timeout'}, + $master->[0]->{'pid'})) + { + + $tinfo->{'comment'}= "Failed to create 'cluster/apply_status' table"; + return 1; + } } mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); mysqld_start($master->[1],$tinfo->{'master_opt'},[]); } - if ( $tinfo->{'master_restart'} ) - { - # Save this test case information, so next can examine it - $master->[0]->{'running_master_is_special'}= $tinfo; - } + # Save this test case information, so next can examine it + $master->[0]->{'running_master_options'}= $tinfo; } elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) { @@ -3664,12 +3862,10 @@ sub run_testcase_start_servers($) { im_create_defaults_file($instance_manager); - unless ( mtr_im_start($instance_manager, $tinfo->{im_opts}) ) + if ( ! mtr_im_start($instance_manager, $tinfo->{im_opts}) ) { - report_failure_and_restart($tinfo); - mtr_report("Failed to start Instance Manager. " . - "The test '$tname' is marked as failed."); - return; + $tinfo->{'comment'}= "Failed to start Instance Manager. "; + return 1; } } @@ -3682,7 +3878,7 @@ sub run_testcase_start_servers($) { restore_slave_databases($tinfo->{'slave_num'}); - do_before_start_slave($tname,$tinfo->{'slave_sh'}); + do_before_start_slave($tinfo); if ( ! $opt_skip_ndbcluster_slave and !$clusters->[1]->{'pid'} and @@ -3702,12 +3898,8 @@ sub run_testcase_start_servers($) { } } - if ( $tinfo->{'slave_restart'} ) - { - # Save this test case information, so next can examine it - $slave->[0]->{'running_slave_is_special'}= $tinfo; - } - + # Save this test case information, so next can examine it + $slave->[0]->{'running_slave_options'}= $tinfo; } # Wait for clusters to start @@ -3719,7 +3911,8 @@ sub run_testcase_start_servers($) { if (ndbcluster_wait_started($cluster, "")) { # failed to start - mtr_report("Start of $cluster->{'name'} cluster failed, "); + $tinfo->{'comment'}= "Start of $cluster->{'name'} cluster failed"; + return 1; } } @@ -3731,9 +3924,13 @@ sub run_testcase_start_servers($) { if (mysqld_wait_started($mysqld)) { - mtr_warning("Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"); + # failed to start + $tinfo->{'comment'}= + "Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"; + return 1; } } + return 0; } # @@ -3741,6 +3938,10 @@ sub run_testcase_start_servers($) { # Before a testcase, run in record mode, save result file to var # After testcase, run and compare with the recorded file, they should be equal! # +# RETURN VALUE +# 0 OK +# 1 Check failed +# sub run_check_testcase ($$) { my $mode= shift; @@ -3774,7 +3975,7 @@ sub run_check_testcase ($$) { my $res = mtr_run_test($exe_mysqltest,$args, "include/check-testcase.test", "", "", ""); - if ( $res == 1 and $mode = "after") + if ( $res == 1 and $mode eq "after") { mtr_run("diff",["-u", "$opt_vardir/tmp/$name.result", @@ -3785,6 +3986,7 @@ sub run_check_testcase ($$) { { mtr_error("Could not execute 'check-testcase' $mode testcase"); } + return $res; } @@ -3856,11 +4058,6 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--big-test"); } - if ( $opt_valgrind ) - { - mtr_add_arg($args, "--valgrind"); - } - if ( $opt_compress ) { mtr_add_arg($args, "--compress"); @@ -3874,7 +4071,7 @@ sub run_mysqltest ($) { if ( $opt_debug ) { mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", - $opt_vardir_trace); + $path_vardir_trace); } if ( $opt_ssl_supported ) @@ -3971,11 +4168,6 @@ sub run_mysqltest ($) { } } - # ------------------------------------------------------- - # Init variables that change for each testcase - # ------------------------------------------------------- - $ENV{'TZ'}= $tinfo->{'timezone'}; - my $res = mtr_run_test($exe,$args,"","",$path_timefile,""); if ( $opt_check_testcases ) @@ -3984,7 +4176,11 @@ sub run_mysqltest ($) { { if ($mysqld->{'pid'}) { - run_check_testcase("after", $mysqld); + if (run_check_testcase("after", $mysqld)) + { + # Check failed, mark the test case with that info + $tinfo->{'check_testcase_failed'}= 1; + } } } } @@ -4205,9 +4401,7 @@ sub usage ($) { print STDERR <<HERE; -mysql-test-run [ OPTIONS ] [ TESTCASE ] - -FIXME when is TESTCASE arg used or not?! +$0 [ OPTIONS ] [ TESTCASE ] Options to control what engine/variation to run @@ -4231,6 +4425,9 @@ Options to control directories to use vardir=DIR The directory where files generated from the test run is stored (default: ./var). Specifying a ramdisk or tmpfs will speed up tests. + mem=DIR Run testsuite in "memory" using tmpfs if + available(default: /dev/shm) + Options to control what test suites or cases to run diff --git a/mysql-test/r/binlog_row_mix_innodb_myisam.result b/mysql-test/r/binlog_row_mix_innodb_myisam.result index a192d243bb0..e063d7371a9 100644 --- a/mysql-test/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/r/binlog_row_mix_innodb_myisam.result @@ -220,7 +220,7 @@ select (@before:=unix_timestamp())*0; (@before:=unix_timestamp())*0 0 begin; - select * from t1 for update; +select * from t1 for update; insert into t2 values (20); ERROR HY000: Lock wait timeout exceeded; try restarting transaction select (@after:=unix_timestamp())*0; diff --git a/mysql-test/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/r/binlog_stm_mix_innodb_myisam.result index 95b6eb953a2..8ab6840d441 100644 --- a/mysql-test/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/r/binlog_stm_mix_innodb_myisam.result @@ -195,7 +195,7 @@ select (@before:=unix_timestamp())*0; (@before:=unix_timestamp())*0 0 begin; - select * from t1 for update; +select * from t1 for update; insert into t2 values (20); ERROR HY000: Lock wait timeout exceeded; try restarting transaction select (@after:=unix_timestamp())*0; diff --git a/mysql-test/r/check.result b/mysql-test/r/check.result index 4c565f4f1b1..60806e7393e 100644 --- a/mysql-test/r/check.result +++ b/mysql-test/r/check.result @@ -1,6 +1,6 @@ drop table if exists t1; create table t1(n int not null, key(n), key(n), key(n), key(n)); - check table t1 extended; +check table t1 extended; insert into t1 values (200000); Table Op Msg_type Msg_text test.t1 check status OK diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index 222d4de8059..32ca47e20d2 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -4913,8 +4913,7 @@ bonfire Colombo nondecreasing DROP TABLE t1; -ALTER TABLE t2 RENAME t1 -#; +ALTER TABLE t2 RENAME t1; DROP TABLE t1; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index 53b2ea8c84a..24f1b654733 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -79,9 +79,9 @@ drop table if exists t1; create table t1 (i int); lock tables t1 read; create database mysqltest; - drop table t1; +drop table t1; show open tables; - drop database mysqltest; +drop database mysqltest; select 1; 1 1 diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index a7f5e5e8fec..7eb7fd16edb 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -9,13 +9,13 @@ n flush tables with read lock; drop table t2; ERROR HY000: Can't execute the query because you have a conflicting read lock - drop table t2; +drop table t2; unlock tables; create database mysqltest; create table mysqltest.t1(n int); insert into mysqltest.t1 values (23); flush tables with read lock; - drop database mysqltest; +drop database mysqltest; select * from mysqltest.t1; n 23 @@ -51,7 +51,7 @@ drop table t1, t2, t3; create table t1 (c1 int); create table t2 (c1 int); lock table t1 write; - flush tables with read lock; - insert into t2 values(1); +flush tables with read lock; +insert into t2 values(1); unlock tables; drop table t1, t2; diff --git a/mysql-test/r/flush_block_commit.result b/mysql-test/r/flush_block_commit.result index e4a9dfcfff1..56f8acab896 100644 --- a/mysql-test/r/flush_block_commit.result +++ b/mysql-test/r/flush_block_commit.result @@ -5,7 +5,7 @@ insert into t1 values(1); flush tables with read lock; select * from t1; a - commit; +commit; select * from t1; a unlock tables; @@ -14,8 +14,8 @@ select * from t1 for update; a 1 begin; - select * from t1 for update; - flush tables with read lock; +select * from t1 for update; +flush tables with read lock; commit; a 1 @@ -45,7 +45,7 @@ flush tables with read lock; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 102 - commit; +commit; show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 102 diff --git a/mysql-test/r/flush_read_lock_kill.result b/mysql-test/r/flush_read_lock_kill.result index dfdcf51457a..6703b6bd533 100644 --- a/mysql-test/r/flush_read_lock_kill.result +++ b/mysql-test/r/flush_read_lock_kill.result @@ -1,7 +1,7 @@ drop table if exists t1; create table t1 (kill_id int); insert into t1 values(connection_id()); - flush tables with read lock; +flush tables with read lock; select ((@id := kill_id) - kill_id) from t1; ((@id := kill_id) - kill_id) 0 diff --git a/mysql-test/r/flush_table.result b/mysql-test/r/flush_table.result index b29c83eb574..8821bade6b4 100644 --- a/mysql-test/r/flush_table.result +++ b/mysql-test/r/flush_table.result @@ -9,7 +9,7 @@ test.t1 check status OK unlock tables; lock table t1 read; lock table t1 read; - flush table t1; +flush table t1; select * from t1; a 1 @@ -19,7 +19,7 @@ a 1 unlock tables; lock table t1 write; - lock table t1 read; +lock table t1 read; flush table t1; select * from t1; a @@ -27,7 +27,7 @@ a unlock tables; unlock tables; lock table t1 read; - lock table t1 write; +lock table t1 write; flush table t1; select * from t1; a diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result index 1a5e64978e6..715f319198c 100644 --- a/mysql-test/r/func_compress.result +++ b/mysql-test/r/func_compress.result @@ -79,6 +79,16 @@ uncompress(a) uncompressed_length(a) NULL NULL a 1 drop table t1; +create table t1(a blob); +insert into t1 values ('0'), (NULL), ('0'); +select compress(a), compress(a) from t1; +select compress(a) is null from t1; +compress(a) is null +0 +1 +0 +drop table t1; +End of 4.1 tests create table t1 (a varchar(32) not null); insert into t1 values ('foo'); explain select * from t1 where uncompress(a) is null; diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index 841d13a6ea6..ac5709260fd 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -71,3 +71,17 @@ NULL NULL NULL drop table t1; +End of 4.1 tests +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 DAY; +CAST('2006-09-26' AS DATE) + INTERVAL 1 DAY +2006-09-27 +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 MONTH; +CAST('2006-09-26' AS DATE) + INTERVAL 1 MONTH +2006-10-26 +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 YEAR; +CAST('2006-09-26' AS DATE) + INTERVAL 1 YEAR +2007-09-26 +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 WEEK; +CAST('2006-09-26' AS DATE) + INTERVAL 1 WEEK +2006-10-03 +End of 5.0 tests diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index f383a717a85..3ebf071a5bb 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -63,7 +63,7 @@ FROM t1 WHERE conn = 'default'; IS_USED_LOCK('bug16501') = connection_id 1 - SELECT GET_LOCK('bug16501',600); +SELECT GET_LOCK('bug16501',600); SELECT IS_USED_LOCK('bug16501') = CONNECTION_ID(); IS_USED_LOCK('bug16501') = CONNECTION_ID() 1 diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index 7e9bba9710c..29ceb6ecaa4 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -107,7 +107,9 @@ subtime("02:01:01.999999", "01:01:01.999999") 01:00:00.000000 select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002") -8807:59:59.999999 +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '8807:59:59.999999' select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") 46:58:57.999999 @@ -219,13 +221,16 @@ SELECT TIMEDIFF(t1, t4) As ttt, TIMEDIFF(t2, t3) As qqq, TIMEDIFF(t3, t2) As eee, TIMEDIFF(t2, t4) As rrr from test; ttt qqq eee rrr -744:00:00 NULL NULL NULL -26305:01:02 22:58:58 -22:58:58 NULL --26305:01:02 -22:58:58 22:58:58 NULL +838:59:59 22:58:58 -22:58:58 NULL +-838:59:59 -22:58:58 22:58:58 NULL NULL 26:02:02 -26:02:02 NULL 00:00:00 -26:02:02 26:02:02 NULL NULL NULL NULL NULL NULL NULL NULL NULL 00:00:00 -24:00:00 24:00:00 NULL +Warnings: +Warning 1292 Truncated incorrect time value: '26305:01:02' +Warning 1292 Truncated incorrect time value: '-26305:01:02' drop table t1, test; select addtime("-01:01:01.01", "-23:59:59.1") as a; a @@ -235,7 +240,9 @@ a 10000 select microsecond(19971231235959.01) as a; a -10000 +0 +Warnings: +Warning 1292 Truncated incorrect time value: '19971231235959.01' select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; a 1997-12-31 00:00:10.090000 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 82c361edd39..7cafd641dd6 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -339,7 +339,9 @@ extract(DAY_MINUTE FROM "02 10:11:12") 21011 select extract(DAY_SECOND FROM "225 10:11:12"); extract(DAY_SECOND FROM "225 10:11:12") -225101112 +8385959 +Warnings: +Warning 1292 Truncated incorrect time value: '225 10:11:12' select extract(HOUR FROM "1999-01-02 10:11:12"); extract(HOUR FROM "1999-01-02 10:11:12") 10 @@ -612,7 +614,7 @@ date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) 2003-01-03 01:01:01 select date_add(date,INTERVAL "1" WEEK) from t1; date_add(date,INTERVAL "1" WEEK) -2003-01-09 00:00:00 +2003-01-09 select date_add(date,INTERVAL "1" QUARTER) from t1; date_add(date,INTERVAL "1" QUARTER) 2003-04-02 @@ -621,7 +623,7 @@ timestampadd(MINUTE, 1, date) 2003-01-02 00:01:00 select timestampadd(WEEK, 1, date) from t1; timestampadd(WEEK, 1, date) -2003-01-09 00:00:00 +2003-01-09 select timestampadd(SQL_TSI_SECOND, 1, date) from t1; timestampadd(SQL_TSI_SECOND, 1, date) 2003-01-02 00:00:01 @@ -902,6 +904,93 @@ fmtddate field2 Sep-4 12:00AM abcd DROP TABLE testBug8868; SET NAMES DEFAULT; +SELECT SEC_TO_TIME(3300000); +SEC_TO_TIME(3300000) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '3300000' +SELECT SEC_TO_TIME(3300000)+0; +SEC_TO_TIME(3300000)+0 +8385959.000000 +Warnings: +Warning 1292 Truncated incorrect time value: '3300000' +SELECT SEC_TO_TIME(3600 * 4294967296); +SEC_TO_TIME(3600 * 4294967296) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '15461882265600' +SELECT TIME_TO_SEC('916:40:00'); +TIME_TO_SEC('916:40:00') +3020399 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT ADDTIME('500:00:00', '416:40:00'); +ADDTIME('500:00:00', '416:40:00') +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT ADDTIME('916:40:00', '416:40:00'); +ADDTIME('916:40:00', '416:40:00') +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +Warning 1292 Truncated incorrect time value: '1255:39:59' +SELECT SUBTIME('916:40:00', '416:40:00'); +SUBTIME('916:40:00', '416:40:00') +422:19:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT SUBTIME('-916:40:00', '416:40:00'); +SUBTIME('-916:40:00', '416:40:00') +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '-916:40:00' +Warning 1292 Truncated incorrect time value: '-1255:39:59' +SELECT MAKETIME(916,0,0); +MAKETIME(916,0,0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:00:00' +SELECT MAKETIME(4294967296, 0, 0); +MAKETIME(4294967296, 0, 0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '4294967296:00:00' +SELECT MAKETIME(-4294967296, 0, 0); +MAKETIME(-4294967296, 0, 0) +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '-4294967296:00:00' +SELECT MAKETIME(0, 4294967296, 0); +MAKETIME(0, 4294967296, 0) +NULL +SELECT MAKETIME(0, 0, 4294967296); +MAKETIME(0, 0, 4294967296) +NULL +SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); +MAKETIME(CAST(-1 AS UNSIGNED), 0, 0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '18446744073709551615:00:00' +SELECT EXTRACT(HOUR FROM '100000:02:03'); +EXTRACT(HOUR FROM '100000:02:03') +838 +Warnings: +Warning 1292 Truncated incorrect time value: '100000:02:03' +CREATE TABLE t1(f1 TIME); +INSERT INTO t1 VALUES('916:00:00 a'); +Warnings: +Warning 1265 Data truncated for column 'f1' at row 1 +Warning 1264 Out of range value adjusted for column 'f1' at row 1 +SELECT * FROM t1; +f1 +838:59:59 +DROP TABLE t1; +SELECT SEC_TO_TIME(CAST(-1 AS UNSIGNED)); +SEC_TO_TIME(CAST(-1 AS UNSIGNED)) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '18446744073709551615' (select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H) union (select time_format(timediff(now(), DATE_SUB(now(),INTERVAL 5 DAY)),'%H') As H); diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index 79ba073a856..4b089c1d5e9 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -336,12 +336,12 @@ drop database mysqltest_1; set password = password("changed"); ERROR 42000: Access denied for user ''@'localhost' to database 'mysql' lock table mysql.user write; - flush privileges; - grant all on *.* to 'mysqltest_1'@'localhost'; +flush privileges; +grant all on *.* to 'mysqltest_1'@'localhost'; unlock tables; lock table mysql.user write; - set password for 'mysqltest_1'@'localhost' = password(''); - revoke all on *.* from 'mysqltest_1'@'localhost'; +set password for 'mysqltest_1'@'localhost' = password(''); +revoke all on *.* from 'mysqltest_1'@'localhost'; unlock tables; drop user 'mysqltest_1'@'localhost'; create database TESTDB; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 89569d918ca..1bd50612a3f 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -476,7 +476,7 @@ handler t1 read first; c1 1 send the below to another connection, do not wait for the result - optimize table t1; +optimize table t1; proceed with the normal connection handler t1 read next; c1 @@ -502,7 +502,7 @@ flush tables with read lock; drop table t1; ERROR HY000: Can't execute the query because you have a conflicting read lock send the below to another connection, do not wait for the result - drop table t1; +drop table t1; proceed with the normal connection select * from t1; c1 diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index 8edf191b1b0..beb1a40c318 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -476,7 +476,7 @@ handler t1 read first; c1 1 send the below to another connection, do not wait for the result - optimize table t1; +optimize table t1; proceed with the normal connection handler t1 read next; c1 @@ -502,7 +502,7 @@ flush tables with read lock; drop table t1; ERROR HY000: Can't execute the query because you have a conflicting read lock send the below to another connection, do not wait for the result - drop table t1; +drop table t1; proceed with the normal connection select * from t1; c1 diff --git a/mysql-test/r/innodb_notembedded.result b/mysql-test/r/innodb_notembedded.result index 9aac20e515d..cc13a429dfc 100644 --- a/mysql-test/r/innodb_notembedded.result +++ b/mysql-test/r/innodb_notembedded.result @@ -10,7 +10,7 @@ start transaction; select f1(); f1() 100 - update t1 set col2=0 where col1=1; +update t1 set col2=0 where col1=1; select * from t1; col1 col2 1 100 diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index b78c677fb02..cf5486d1091 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -22,7 +22,7 @@ create table t2 (id int unsigned not null); insert into t2 select id from t1; create table t3 (kill_id int); insert into t3 values(connection_id()); - select id from t1 where id in (select distinct id from t2); +select id from t1 where id in (select distinct id from t2); select ((@id := kill_id) - kill_id) from t3; ((@id := kill_id) - kill_id) 0 @@ -32,7 +32,7 @@ drop table t1, t2, t3; select get_lock("a", 10); get_lock("a", 10) 1 - select get_lock("a", 10); +select get_lock("a", 10); get_lock("a", 10) NULL select 1; diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index 8ff02d898a3..2445b3e0c69 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -2,8 +2,8 @@ drop table if exists t1,t2; create table t1(n int); insert into t1 values (1); lock tables t1 write; - update low_priority t1 set n = 4; - select n from t1; +update low_priority t1 set n = 4; +select n from t1; unlock tables; n 4 @@ -11,8 +11,8 @@ drop table t1; create table t1(n int); insert into t1 values (1); lock tables t1 read; - update low_priority t1 set n = 4; - select n from t1; +update low_priority t1 set n = 4; +select n from t1; unlock tables; n 1 @@ -23,7 +23,7 @@ insert into t1 values(1,1); insert into t1 values(2,2); insert into t2 values(1,2); lock table t1 read; - update t1,t2 set c=a where b=d; +update t1,t2 set c=a where b=d; select c from t2; c 2 @@ -32,14 +32,14 @@ drop table t2; create table t1 (a int); create table t2 (a int); lock table t1 write, t2 write; - insert t1 select * from t2; +insert t1 select * from t2; drop table t2; ERROR 42S02: Table 'test.t2' doesn't exist drop table t1; create table t1 (a int); create table t2 (a int); lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write; - insert t1 select * from t2; +insert t1 select * from t2; drop table t2; ERROR 42S02: Table 'test.t2' doesn't exist drop table t1; @@ -54,7 +54,7 @@ use mysql; LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; FLUSH TABLES; use mysql; - SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; +SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; OPTIMIZE TABLES columns_priv, db, host, user; Table Op Msg_type Msg_text mysql.columns_priv optimize status OK @@ -68,14 +68,14 @@ use test; use test; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; - FLUSH TABLES WITH READ LOCK; +FLUSH TABLES WITH READ LOCK; CREATE TABLE t2 (c1 int); UNLOCK TABLES; UNLOCK TABLES; DROP TABLE t1, t2; CREATE TABLE t1 (c1 int); LOCK TABLE t1 WRITE; - FLUSH TABLES WITH READ LOCK; +FLUSH TABLES WITH READ LOCK; CREATE TABLE t2 AS SELECT * FROM t1; ERROR HY000: Table 't2' was not locked with LOCK TABLES UNLOCK TABLES; @@ -83,7 +83,7 @@ UNLOCK TABLES; DROP TABLE t1; CREATE DATABASE mysqltest_1; FLUSH TABLES WITH READ LOCK; - DROP DATABASE mysqltest_1; +DROP DATABASE mysqltest_1; DROP DATABASE mysqltest_1; ERROR HY000: Can't execute the query because you have a conflicting read lock UNLOCK TABLES; @@ -91,7 +91,7 @@ DROP DATABASE mysqltest_1; ERROR HY000: Can't drop database 'mysqltest_1'; database doesn't exist create table t1 (f1 int(12) unsigned not null auto_increment, primary key(f1)) engine=innodb; lock tables t1 write; - alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // - alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // +alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // +alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; alter table t1 auto_increment=0; // unlock tables; drop table t1; diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index a9683cc7c56..8df848fb2d0 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -39,14 +39,14 @@ ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL inste lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; unlock tables; lock tables mysql.general_log READ LOCAL; - flush logs; +flush logs; unlock tables; select "Mark that we woke up from flush logs in the test" as "test passed"; test passed Mark that we woke up from flush logs in the test lock tables mysql.general_log READ LOCAL; - truncate mysql.general_log; +truncate mysql.general_log; unlock tables; select "Mark that we woke up from TRUNCATE in the test" as "test passed"; diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 3ed0222fcdb..6d8e5dfdf2c 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -509,8 +509,8 @@ create table t2 (a int); insert into t2 values (10), (20), (30); create view v1 as select a as b, a/10 as a from t2; lock table t1 write; - alter table t1 add column c int default 100 after a; - update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a; +alter table t1 add column c int default 100 after a; +update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a; unlock tables; select * from t1; a c b diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index 1053b1918fb..86ac7a8d72d 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -149,4 +149,17 @@ ERROR at line 1: USE must be followed by a database name \\ '; '; +create table t17583 (a int); +insert into t17583 (a) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +select count(*) from t17583; +count(*) +1280 +drop table t17583; End of 5.0 tests diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index ce9fb6941f3..a0fce5f483f 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -152,8 +152,38 @@ mysqltest: At line 1: Missing delimiter mysqltest: At line 1: End of line junk detected: "sleep 7 # Another comment " +mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: End of line junk detected: "disconnect default + +# +# comment +# comment2 + +# comment 3 +--disable_query_log +" +mysqltest: At line 1: End of line junk detected: "disconnect default # comment +# comment part2 + +# comment 3 +--disable_query_log +" mysqltest: At line 1: Extra delimiter ";" found mysqltest: At line 1: Extra delimiter ";" found +mysqltest: At line 1: Missing argument(s) to 'error' +mysqltest: At line 1: Missing argument(s) to 'error' +mysqltest: At line 1: The sqlstate definition must start with an uppercase S +mysqltest: At line 1: The error name definition must start with an uppercase E +mysqltest: At line 1: Invalid argument to error: '9eeeee' - the errno may only consist of digits[0-9] +mysqltest: At line 1: Invalid argument to error: '1sssss' - the errno may only consist of digits[0-9] +mysqltest: At line 1: The sqlstate must be exactly 5 chars long +mysqltest: At line 1: The sqlstate may only consist of digits[0-9] and _uppercase_ letters +mysqltest: At line 1: The sqlstate must be exactly 5 chars long +mysqltest: At line 1: Unknown SQL error name 'E9999' +mysqltest: At line 1: Invalid argument to error: '999e9' - the errno may only consist of digits[0-9] +mysqltest: At line 1: Invalid argument to error: '9b' - the errno may only consist of digits[0-9] +mysqltest: At line 1: Too many errorcodes specified MySQL "MySQL" MySQL: The world''s most popular open source database @@ -239,7 +269,7 @@ mysqltest: At line 1: Missing assignment operator in let 1 # Execute: echo $success ; 1 -mysqltest: At line 1: Missing file name in source +mysqltest: At line 1: Missing required argument 'filename' to command 'source' mysqltest: At line 1: Could not open file ./non_existingFile mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": At line 1: Source directives are nesting too deep mysqltest: In included file "MYSQLTEST_VARDIR/tmp/error.sql": At line 1: query 'garbage ' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 @@ -332,16 +362,16 @@ Counter is greater than 0, (counter=10) Counter is not 0, (counter=0) 1 Testing while with not -mysqltest: In included file "./include/mysqltest_while.inc": At line 64: Nesting too deeply +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest_while.inc": At line 64: Nesting too deeply mysqltest: At line 1: missing '(' in while mysqltest: At line 1: missing ')' in while mysqltest: At line 1: Missing '{' after while. Found "dec $i" mysqltest: At line 1: Stray '}' - end of block before beginning mysqltest: At line 1: Stray 'end' command - end of block before beginning -mysqltest: At line 1: query '' failed: 1065: Query was empty +mysqltest: At line 1: query '{' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '{' at line 1 mysqltest: At line 1: Missing '{' after while. Found "echo hej" mysqltest: At line 3: Missing end of block -mysqltest: At line 1: Missing newline between while and '{' +mysqltest: At line 3: Missing end of block mysqltest: At line 1: missing '(' in if mysqltest: At line 1: Stray 'end' command - end of block before beginning select "b" bs col1, "c" bs col2; @@ -371,17 +401,15 @@ mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 mysqltest: At line 1: Invalid integer argument "10!" mysqltest: At line 1: End of line junk detected: "!" mysqltest: At line 1: Invalid integer argument "a" -mysqltest: At line 1: Syntax error in connect - expected '(' found 'mysqltest: At line 1: Missing connection host -mysqltest: At line 1: Missing connection host -mysqltest: At line 1: Missing connection user -mysqltest: At line 1: Missing connection user -mysqltest: At line 1: Missing connection password -mysqltest: At line 1: Missing connection db -mysqltest: At line 1: Could not open connection 'con2': 1049 Unknown database 'illegal_db' +mysqltest: At line 1: Missing required argument 'connection name' to command 'connect' +mysqltest: At line 1: Missing required argument 'connection name' to command 'connect' +mysqltest: At line 1: Missing required argument 'host' to command 'connect' +mysqltest: At line 1: Missing required argument 'host' to command 'connect' +mysqltest: At line 1: query 'connect con2,localhost,root,,illegal_db' failed: 1049: Unknown database 'illegal_db' mysqltest: At line 1: Illegal argument for port: 'illegal_port' mysqltest: At line 1: Illegal option to connect: SMTP OK -mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 7: Connection limit exhausted - increase MAX_CONS in mysqltest.c +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 7: Connection limit exhausted, you can have max 128 connections mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 3: connection 'test_con1' not found in connection pool mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 2: Connection test_con1 already exists connect(localhost,root,,test,MASTER_PORT,MASTER_SOCKET); @@ -449,7 +477,6 @@ sleep; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sleep' at line 1 ; ERROR 42000: Query was empty -End of 5.0 tests select "b" as col1, "c" as col2; col1 col2 b c @@ -477,4 +504,18 @@ a D 1 1 1 4 drop table t1; -End of 5.1 tests +mysqltest: At line 1: Missing required argument 'filename' to command 'remove_file' +mysqltest: At line 1: Missing required argument 'filename' to command 'write_file' +mysqltest: At line 1: End of file encountered before 'EOF' delimiter was found +mysqltest: At line 1: End of line junk detected: "write_file filename "; +" +mysqltest: At line 1: Missing required argument 'filename' to command 'file_exists' +mysqltest: At line 1: Missing required argument 'from_file' to command 'copy_file' +mysqltest: At line 1: Missing required argument 'to_file' to command 'copy_file' +hello +hello +hello +mysqltest: At line 1: Max delimiter length(16) exceeded +hello +hello +End of tests diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index f3e44a1df60..5a8f5a3137d 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1090,41 +1090,15 @@ drop table t1; create table t1 (a int) engine myisam partition by range (a) subpartition by hash (a) -(partition p0 VALUES LESS THAN (1) DATA DIRECTORY = 'hello/master-data/tmpdata' INDEX DIRECTORY = 'hello/master-data/tmpinx' +(partition p0 VALUES LESS THAN (1) DATA DIRECTORY = 'MYSQLTEST_VARDIR/master-data/tmpdata' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/master-data/tmpinx' (SUBPARTITION subpart00, SUBPARTITION subpart01)); -hello/master-data/test/t1.frm -hello/master-data/test/t1.par -hello/master-data/test/t1#P#p0#SP#subpart00.MYD -hello/master-data/test/t1#P#p0#SP#subpart00.MYI -hello/master-data/test/t1#P#p0#SP#subpart01.MYD -hello/master-data/test/t1#P#p0#SP#subpart01.MYI -hello/master-data/tmpdata/t1#P#p0#SP#subpart00.MYD -hello/master-data/tmpdata/t1#P#p0#SP#subpart01.MYD -hello/master-data/tmpinx/t1#P#p0#SP#subpart00.MYI -hello/master-data/tmpinx/t1#P#p0#SP#subpart01.MYI +Checking if file exists before alter ALTER TABLE t1 REORGANIZE PARTITION p0 INTO -(partition p1 VALUES LESS THAN (1) DATA DIRECTORY = 'hello/master-data/tmpdata' INDEX DIRECTORY = 'hello/master-data/tmpinx' +(partition p1 VALUES LESS THAN (1) DATA DIRECTORY = 'MYSQLTEST_VARDIR/master-data/tmpdata' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/master-data/tmpinx' (SUBPARTITION subpart10, SUBPARTITION subpart11), -partition p2 VALUES LESS THAN (2) DATA DIRECTORY = 'hello/master-data/tmpdata' INDEX DIRECTORY = 'hello/master-data/tmpinx' +partition p2 VALUES LESS THAN (2) DATA DIRECTORY = 'MYSQLTEST_VARDIR/master-data/tmpdata' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/master-data/tmpinx' (SUBPARTITION subpart20, SUBPARTITION subpart21)); -hello/master-data/test/t1.frm -hello/master-data/test/t1.par -hello/master-data/test/t1#P#p1#SP#subpart10.MYD -hello/master-data/test/t1#P#p1#SP#subpart10.MYI -hello/master-data/test/t1#P#p1#SP#subpart11.MYD -hello/master-data/test/t1#P#p1#SP#subpart11.MYI -hello/master-data/test/t1#P#p2#SP#subpart20.MYD -hello/master-data/test/t1#P#p2#SP#subpart20.MYI -hello/master-data/test/t1#P#p2#SP#subpart21.MYD -hello/master-data/test/t1#P#p2#SP#subpart21.MYI -hello/master-data/tmpdata/t1#P#p1#SP#subpart10.MYD -hello/master-data/tmpdata/t1#P#p1#SP#subpart11.MYD -hello/master-data/tmpdata/t1#P#p2#SP#subpart20.MYD -hello/master-data/tmpdata/t1#P#p2#SP#subpart21.MYD -hello/master-data/tmpinx/t1#P#p1#SP#subpart10.MYI -hello/master-data/tmpinx/t1#P#p1#SP#subpart11.MYI -hello/master-data/tmpinx/t1#P#p2#SP#subpart20.MYI -hello/master-data/tmpinx/t1#P#p2#SP#subpart21.MYI +Checking if file exists after alter drop table t1; create table t1 (a bigint unsigned not null, primary key(a)) engine = myisam diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index b7dae03bf47..7dadb3207a8 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -499,54 +499,6 @@ create temporary table if not exists t1 (a1 int); execute stmt; drop temporary table t1; deallocate prepare stmt; -CREATE TABLE t1( -ID int(10) unsigned NOT NULL auto_increment, -Member_ID varchar(15) NOT NULL default '', -Action varchar(12) NOT NULL, -Action_Date datetime NOT NULL, -Track varchar(15) default NULL, -User varchar(12) default NULL, -Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update -CURRENT_TIMESTAMP, -PRIMARY KEY (ID), -KEY Action (Action), -KEY Action_Date (Action_Date) -); -INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES -('111111', 'Disenrolled', '2006-03-01', 'CAD' ), -('111111', 'Enrolled', '2006-03-01', 'CAD' ), -('111111', 'Disenrolled', '2006-07-03', 'CAD' ), -('222222', 'Enrolled', '2006-03-07', 'CAD' ), -('222222', 'Enrolled', '2006-03-07', 'CHF' ), -('222222', 'Disenrolled', '2006-08-02', 'CHF' ), -('333333', 'Enrolled', '2006-03-01', 'CAD' ), -('333333', 'Disenrolled', '2006-03-01', 'CAD' ), -('444444', 'Enrolled', '2006-03-01', 'CAD' ), -('555555', 'Disenrolled', '2006-03-01', 'CAD' ), -('555555', 'Enrolled', '2006-07-21', 'CAD' ), -('555555', 'Disenrolled', '2006-03-01', 'CHF' ), -('666666', 'Enrolled', '2006-02-09', 'CAD' ), -('666666', 'Enrolled', '2006-05-12', 'CHF' ), -('666666', 'Disenrolled', '2006-06-01', 'CAD' ); -PREPARE STMT FROM -"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 - WHERE Member_ID=? AND Action='Enrolled' AND - (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 - WHERE Member_ID=? - GROUP BY Track - HAVING Track>='CAD' AND - MAX(Action_Date)>'2006-03-01')"; -SET @id='111111'; -EXECUTE STMT USING @id,@id; -GROUP_CONCAT(Track SEPARATOR ', ') -NULL -SET @id='222222'; -EXECUTE STMT USING @id,@id; -GROUP_CONCAT(Track SEPARATOR ', ') -CAD -DEALLOCATE PREPARE STMT; -DROP TABLE t1; -End of 4.1 tests create table t1 (a varchar(20)); insert into t1 values ('foo'); prepare stmt FROM 'SELECT char_length (a) FROM t1'; @@ -564,77 +516,6 @@ SELECT FOUND_ROWS(); FOUND_ROWS() 2 deallocate prepare stmt; -create table t1 (a char(3) not null, b char(3) not null, -c char(3) not null, primary key (a, b, c)); -create table t2 like t1; -prepare stmt from -"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b) - where t1.a=1"; -execute stmt; -a -execute stmt; -a -execute stmt; -a -prepare stmt from -"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from -(t1 left outer join t2 on t2.a=? and t1.b=t2.b) -left outer join t2 t3 on t3.a=? where t1.a=?"; -set @a:=1, @b:=1, @c:=1; -execute stmt using @a, @b, @c; -a b c a b c -execute stmt using @a, @b, @c; -a b c a b c -execute stmt using @a, @b, @c; -a b c a b c -deallocate prepare stmt; -drop table t1,t2; -SET @aux= "SELECT COUNT(*) - FROM INFORMATION_SCHEMA.COLUMNS A, - INFORMATION_SCHEMA.COLUMNS B - WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA - AND A.TABLE_NAME = B.TABLE_NAME - AND A.COLUMN_NAME = B.COLUMN_NAME AND - A.TABLE_NAME = 'user'"; -prepare my_stmt from @aux; -execute my_stmt; -COUNT(*) -39 -execute my_stmt; -COUNT(*) -39 -execute my_stmt; -COUNT(*) -39 -deallocate prepare my_stmt; -drop procedure if exists p1| -drop table if exists t1| -create table t1 (id int)| -insert into t1 values(1)| -create procedure p1(a int, b int) -begin -declare c int; -select max(id)+1 into c from t1; -insert into t1 select a+b; -insert into t1 select a-b; -insert into t1 select a-c; -end| -set @a= 3, @b= 4| -prepare stmt from "call p1(?, ?)"| -execute stmt using @a, @b| -execute stmt using @a, @b| -select * from t1| -id -1 -7 --1 -1 -7 --1 --5 -deallocate prepare stmt| -drop procedure p1| -drop table t1| drop table if exists t1; Warnings: Note 1051 Unknown table 't1' @@ -698,47 +579,6 @@ id 3 deallocate prepare stmt; drop table t1, t2; -create table t1 (a int); -insert into t1 (a) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); -prepare stmt from "select * from t1 limit ?, ?"; -set @offset=0, @limit=1; -execute stmt using @offset, @limit; -a -1 -select * from t1 limit 0, 1; -a -1 -set @offset=3, @limit=2; -execute stmt using @offset, @limit; -a -4 -5 -select * from t1 limit 3, 2; -a -4 -5 -prepare stmt from "select * from t1 limit ?"; -execute stmt using @limit; -a -1 -2 -prepare stmt from "select * from t1 where a in (select a from t1 limit ?)"; -ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' -prepare stmt from "select * from t1 union all select * from t1 limit ?, ?"; -set @offset=9; -set @limit=2; -execute stmt using @offset, @limit; -a -10 -1 -prepare stmt from "(select * from t1 limit ?, ?) union all - (select * from t1 limit ?, ?) order by a limit ?"; -execute stmt using @offset, @limit, @offset, @limit, @limit; -a -10 -10 -drop table t1; -deallocate prepare stmt; create table t1 (id int); prepare stmt from "insert into t1 (id) select id from t1 union select id from t1"; execute stmt; @@ -839,15 +679,6 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp select ? from t1; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? from t1' at line 1 drop table t1; -CREATE TABLE b12651_T1(a int) ENGINE=MYISAM; -CREATE TABLE b12651_T2(b int) ENGINE=MYISAM; -CREATE VIEW b12651_V1 as SELECT b FROM b12651_T2; -PREPARE b12651 FROM 'SELECT 1 FROM b12651_T1 WHERE a IN (SELECT b FROM b12651_V1)'; -EXECUTE b12651; -1 -DROP VIEW b12651_V1; -DROP TABLE b12651_T1, b12651_T2; -DEALLOCATE PREPARE b12651; prepare stmt from "select @@time_zone"; execute stmt; @@time_zone @@ -1064,6 +895,194 @@ select @@max_prepared_stmt_count, @@prepared_stmt_count; @@max_prepared_stmt_count @@prepared_stmt_count 3 0 set global max_prepared_stmt_count= @old_max_prepared_stmt_count; +drop table if exists t1; +create temporary table if not exists t1 (a1 int); +prepare stmt from "delete t1 from t1 where (cast(a1/3 as unsigned) * 3) = a1"; +drop temporary table t1; +create temporary table if not exists t1 (a1 int); +execute stmt; +drop temporary table t1; +create temporary table if not exists t1 (a1 int); +execute stmt; +drop temporary table t1; +create temporary table if not exists t1 (a1 int); +execute stmt; +drop temporary table t1; +deallocate prepare stmt; +CREATE TABLE t1( +ID int(10) unsigned NOT NULL auto_increment, +Member_ID varchar(15) NOT NULL default '', +Action varchar(12) NOT NULL, +Action_Date datetime NOT NULL, +Track varchar(15) default NULL, +User varchar(12) default NULL, +Date_Updated timestamp NOT NULL default CURRENT_TIMESTAMP on update +CURRENT_TIMESTAMP, +PRIMARY KEY (ID), +KEY Action (Action), +KEY Action_Date (Action_Date) +); +INSERT INTO t1(Member_ID, Action, Action_Date, Track) VALUES +('111111', 'Disenrolled', '2006-03-01', 'CAD' ), +('111111', 'Enrolled', '2006-03-01', 'CAD' ), +('111111', 'Disenrolled', '2006-07-03', 'CAD' ), +('222222', 'Enrolled', '2006-03-07', 'CAD' ), +('222222', 'Enrolled', '2006-03-07', 'CHF' ), +('222222', 'Disenrolled', '2006-08-02', 'CHF' ), +('333333', 'Enrolled', '2006-03-01', 'CAD' ), +('333333', 'Disenrolled', '2006-03-01', 'CAD' ), +('444444', 'Enrolled', '2006-03-01', 'CAD' ), +('555555', 'Disenrolled', '2006-03-01', 'CAD' ), +('555555', 'Enrolled', '2006-07-21', 'CAD' ), +('555555', 'Disenrolled', '2006-03-01', 'CHF' ), +('666666', 'Enrolled', '2006-02-09', 'CAD' ), +('666666', 'Enrolled', '2006-05-12', 'CHF' ), +('666666', 'Disenrolled', '2006-06-01', 'CAD' ); +PREPARE STMT FROM +"SELECT GROUP_CONCAT(Track SEPARATOR ', ') FROM t1 + WHERE Member_ID=? AND Action='Enrolled' AND + (Track,Action_Date) IN (SELECT Track, MAX(Action_Date) FROM t1 + WHERE Member_ID=? + GROUP BY Track + HAVING Track>='CAD' AND + MAX(Action_Date)>'2006-03-01')"; +SET @id='111111'; +EXECUTE STMT USING @id,@id; +GROUP_CONCAT(Track SEPARATOR ', ') +NULL +SET @id='222222'; +EXECUTE STMT USING @id,@id; +GROUP_CONCAT(Track SEPARATOR ', ') +CAD +DEALLOCATE PREPARE STMT; +DROP TABLE t1; +End of 4.1 tests +create table t1 (a varchar(20)); +insert into t1 values ('foo'); +prepare stmt FROM 'SELECT char_length (a) FROM t1'; +ERROR 42000: FUNCTION test.char_length does not exist +drop table t1; +create table t1 (a char(3) not null, b char(3) not null, +c char(3) not null, primary key (a, b, c)); +create table t2 like t1; +prepare stmt from +"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b) + where t1.a=1"; +execute stmt; +a +execute stmt; +a +execute stmt; +a +prepare stmt from +"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from +(t1 left outer join t2 on t2.a=? and t1.b=t2.b) +left outer join t2 t3 on t3.a=? where t1.a=?"; +set @a:=1, @b:=1, @c:=1; +execute stmt using @a, @b, @c; +a b c a b c +execute stmt using @a, @b, @c; +a b c a b c +execute stmt using @a, @b, @c; +a b c a b c +deallocate prepare stmt; +drop table t1,t2; +SET @aux= "SELECT COUNT(*) + FROM INFORMATION_SCHEMA.COLUMNS A, + INFORMATION_SCHEMA.COLUMNS B + WHERE A.TABLE_SCHEMA = B.TABLE_SCHEMA + AND A.TABLE_NAME = B.TABLE_NAME + AND A.COLUMN_NAME = B.COLUMN_NAME AND + A.TABLE_NAME = 'user'"; +prepare my_stmt from @aux; +execute my_stmt; +COUNT(*) +39 +execute my_stmt; +COUNT(*) +39 +execute my_stmt; +COUNT(*) +39 +deallocate prepare my_stmt; +drop procedure if exists p1| +drop table if exists t1| +create table t1 (id int)| +insert into t1 values(1)| +create procedure p1(a int, b int) +begin +declare c int; +select max(id)+1 into c from t1; +insert into t1 select a+b; +insert into t1 select a-b; +insert into t1 select a-c; +end| +set @a= 3, @b= 4| +prepare stmt from "call p1(?, ?)"| +execute stmt using @a, @b| +execute stmt using @a, @b| +select * from t1| +id +1 +7 +-1 +1 +7 +-1 +-5 +deallocate prepare stmt| +drop procedure p1| +drop table t1| +create table t1 (a int); +insert into t1 (a) values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10); +prepare stmt from "select * from t1 limit ?, ?"; +set @offset=0, @limit=1; +execute stmt using @offset, @limit; +a +1 +select * from t1 limit 0, 1; +a +1 +set @offset=3, @limit=2; +execute stmt using @offset, @limit; +a +4 +5 +select * from t1 limit 3, 2; +a +4 +5 +prepare stmt from "select * from t1 limit ?"; +execute stmt using @limit; +a +1 +2 +prepare stmt from "select * from t1 where a in (select a from t1 limit ?)"; +ERROR 42000: This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery' +prepare stmt from "select * from t1 union all select * from t1 limit ?, ?"; +set @offset=9; +set @limit=2; +execute stmt using @offset, @limit; +a +10 +1 +prepare stmt from "(select * from t1 limit ?, ?) union all + (select * from t1 limit ?, ?) order by a limit ?"; +execute stmt using @offset, @limit, @offset, @limit, @limit; +a +10 +10 +drop table t1; +deallocate prepare stmt; +CREATE TABLE b12651_T1(a int) ENGINE=MYISAM; +CREATE TABLE b12651_T2(b int) ENGINE=MYISAM; +CREATE VIEW b12651_V1 as SELECT b FROM b12651_T2; +PREPARE b12651 FROM 'SELECT 1 FROM b12651_T1 WHERE a IN (SELECT b FROM b12651_V1)'; +EXECUTE b12651; +1 +DROP VIEW b12651_V1; +DROP TABLE b12651_T1, b12651_T2; +DEALLOCATE PREPARE b12651; create table t1 (id int); prepare ins_call from "insert into t1 (id) values (1)"; execute ins_call; @@ -1360,27 +1379,48 @@ i 1 DEALLOCATE PREPARE stmt; DROP TABLE t1, t2; +flush status; +prepare sq from 'show status like "slow_queries"'; +execute sq; +Variable_name Value +Slow_queries 0 +prepare no_index from 'select 1 from information_schema.tables limit 1'; +execute sq; +Variable_name Value +Slow_queries 0 +execute no_index; +1 +1 +execute sq; +Variable_name Value +Slow_queries 1 +deallocate prepare no_index; +deallocate prepare sq; End of 5.0 tests. create procedure proc_1() reset query cache; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin reset query cache; return 1; end| +ERROR 0A000: RESET is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 0A000: FLUSH is not allowed in stored function or trigger +ERROR 0A000: RESET is not allowed in stored function or trigger drop function func_1; +drop procedure proc_1; prepare abc from "reset query cache"; execute abc; execute abc; execute abc; deallocate prepare abc; create procedure proc_1() reset master; -drop procedure proc_1; create function func_1() returns int begin reset master; return 1; end| +ERROR 0A000: RESET is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 0A000: FLUSH is not allowed in stored function or trigger +ERROR 0A000: RESET is not allowed in stored function or trigger drop function func_1; +drop procedure proc_1; prepare abc from "reset master"; execute abc; execute abc; @@ -1390,11 +1430,13 @@ create procedure proc_1() reset slave; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin reset slave; return 1; end| +ERROR 0A000: RESET is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 0A000: FLUSH is not allowed in stored function or trigger +ERROR 0A000: RESET is not allowed in stored function or trigger drop function func_1; +drop procedure proc_1; prepare abc from "reset slave"; execute abc; execute abc; @@ -1429,13 +1471,13 @@ call proc_1(); call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush hosts; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush hosts"; execute abc; execute abc; @@ -1445,13 +1487,13 @@ create procedure proc_1() flush privileges; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush privileges; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush privileges"; deallocate prepare abc; create procedure proc_1() flush tables with read lock; @@ -1461,9 +1503,13 @@ call proc_1(); unlock tables; call proc_1(); unlock tables; -drop procedure proc_1; create function func_1() returns int begin flush tables with read lock; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| +select func_1(), func_1(), func_1() from dual; +ERROR 0A000: FLUSH is not allowed in stored function or trigger +drop function func_1; +drop procedure proc_1; prepare abc from "flush tables with read lock"; execute abc; execute abc; @@ -1474,13 +1520,13 @@ create procedure proc_1() flush tables; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush tables; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush tables"; execute abc; execute abc; @@ -1540,13 +1586,13 @@ mysql user 0 0 mysql general_log 1 0 mysql host 0 0 flush tables; -drop procedure proc_1; create function func_1() returns int begin flush tables; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; flush tables; select Host, User from mysql.user limit 0; Host User @@ -1603,13 +1649,13 @@ create procedure proc_1() flush logs; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush logs; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush logs"; execute abc; execute abc; @@ -1619,13 +1665,13 @@ create procedure proc_1() flush status; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush status; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush status"; execute abc; execute abc; @@ -1635,39 +1681,39 @@ create procedure proc_1() flush slave; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush slave; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush slave"; execute abc; execute abc; execute abc; deallocate prepare abc; create procedure proc_1() flush master; -drop procedure proc_1; create function func_1() returns int begin flush master; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush master"; deallocate prepare abc; create procedure proc_1() flush des_key_file; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush des_key_file; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush des_key_file"; execute abc; execute abc; @@ -1677,13 +1723,13 @@ create procedure proc_1() flush user_resources; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; create function func_1() returns int begin flush user_resources; return 1; end| ERROR 0A000: FLUSH is not allowed in stored function or trigger +create function func_1() returns int begin call proc_1(); return 1; end| select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist +ERROR 0A000: FLUSH is not allowed in stored function or trigger drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist +drop procedure proc_1; prepare abc from "flush user_resources"; execute abc; execute abc; @@ -1763,18 +1809,6 @@ Db Name Definer Type Execute at Interval value Interval field Starts Ends Status execute abc; Db Name Definer Type Execute at Interval value Interval field Starts Ends Status deallocate prepare abc; -create procedure proc_1() show scheduler status; -drop procedure proc_1; -create function func_1() returns int begin show scheduler status; return 1; end| -ERROR 0A000: Not allowed to return a result set from a function -select func_1(), func_1(), func_1() from dual; -ERROR 42000: FUNCTION test.func_1 does not exist -drop function func_1; -ERROR 42000: FUNCTION test.func_1 does not exist -prepare abc from "show scheduler status"; -ERROR HY000: This command is not supported in the prepared statement protocol yet -deallocate prepare abc; -ERROR HY000: Unknown prepared statement handler (abc) given to DEALLOCATE PREPARE drop procedure if exists a; create procedure a() select 42; create procedure proc_1(a char(2)) show create procedure a; @@ -1952,11 +1986,11 @@ ERROR HY000: No paths allowed for shared library drop procedure proc_1; create procedure proc_1() install plugin my_plug soname 'some_plugin.so'; call proc_1(); -ERROR HY000: Can't open shared library '/work/mysql-5.1-runtime/mysql-test/lib/mysql/some_plugin.so' (errno: 0 cannot open shared object file: No such file or directory) +ERROR HY000: Can't open shared library call proc_1(); -ERROR HY000: Can't open shared library '/work/mysql-5.1-runtime/mysql-test/lib/mysql/some_plugin.so' (errno: 22 cannot open shared object file: No such file or directory) +ERROR HY000: Can't open shared library call proc_1(); -ERROR HY000: Can't open shared library '/work/mysql-5.1-runtime/mysql-test/lib/mysql/some_plugin.so' (errno: 22 cannot open shared object file: No such file or directory) +ERROR HY000: Can't open shared library drop procedure proc_1; create function func_1() returns int begin install plugin my_plug soname '/tmp/plugin'; return 1; end| ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. @@ -2086,7 +2120,7 @@ drop user pstest_xyz@localhost; deallocate prepare abc; drop event if exists xyz; create function func_1() returns int begin create event xyz on schedule at now() do select 123; return 1; end| -ERROR 0A000: Not allowed to return a result set from a function +ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present select func_1(), func_1(), func_1() from dual; ERROR 42000: FUNCTION test.func_1 does not exist drop function func_1; diff --git a/mysql-test/r/ps_11bugs.result b/mysql-test/r/ps_11bugs.result index c849c25d646..ebe161f46b3 100644 --- a/mysql-test/r/ps_11bugs.result +++ b/mysql-test/r/ps_11bugs.result @@ -130,3 +130,36 @@ prepare st_18492 from 'select * from t1 where 3 in (select (1+1) union select 1) execute st_18492; a drop table t1; +create table t1 (a int, b varchar(4)); +create table t2 (a int, b varchar(4), primary key(a)); +prepare stmt1 from 'insert into t1 (a, b) values (?, ?)'; +prepare stmt2 from 'insert into t2 (a, b) values (?, ?)'; +set @intarg= 11; +set @varchararg= '2222'; +execute stmt1 using @intarg, @varchararg; +execute stmt2 using @intarg, @varchararg; +set @intarg= 12; +execute stmt1 using @intarg, @UNDEFINED; +execute stmt2 using @intarg, @UNDEFINED; +set @intarg= 13; +execute stmt1 using @UNDEFINED, @varchararg; +execute stmt2 using @UNDEFINED, @varchararg; +ERROR 23000: Column 'a' cannot be null +set @intarg= 14; +set @nullarg= Null; +execute stmt1 using @UNDEFINED, @nullarg; +execute stmt2 using @nullarg, @varchararg; +ERROR 23000: Column 'a' cannot be null +select * from t1; +a b +11 2222 +12 NULL +NULL 2222 +NULL NULL +select * from t2; +a b +11 2222 +12 NULL +drop table t1; +drop table t2; +End of 5.0 tests. diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 96289305da1..d5996ee8163 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -934,8 +934,7 @@ abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab zyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcbazyxwvutsrqponmlkjihgfedcba flush query cache; drop table t1, t2; -set GLOBAL query_cache_size=1355776 -#; +set GLOBAL query_cache_size=1355776; flush status; CREATE TABLE t1 ( `date` datetime NOT NULL default '0000-00-00 00:00:00', diff --git a/mysql-test/r/query_cache_notembedded.result b/mysql-test/r/query_cache_notembedded.result index 4226738725a..8e5df012cfb 100644 --- a/mysql-test/r/query_cache_notembedded.result +++ b/mysql-test/r/query_cache_notembedded.result @@ -326,7 +326,7 @@ insert into t1 values(3); set i_var = sleep(3); return 0; end;| - select f1(); +select f1(); select sleep(4); sleep(4) 0 diff --git a/mysql-test/r/rename.result b/mysql-test/r/rename.result index 76c0f4422fe..964babb1228 100644 --- a/mysql-test/r/rename.result +++ b/mysql-test/r/rename.result @@ -43,7 +43,7 @@ Note 1051 Unknown table 't4' CREATE TABLE t1 (a int); CREATE TABLE t3 (a int); FLUSH TABLES WITH READ LOCK; - RENAME TABLE t1 TO t2, t3 to t4; +RENAME TABLE t1 TO t2, t3 to t4; show tables; Tables_in_test t1 diff --git a/mysql-test/r/rpl_err_ignoredtable.result b/mysql-test/r/rpl_err_ignoredtable.result index 27db9c0372c..f211d5d9a2f 100644 --- a/mysql-test/r/rpl_err_ignoredtable.result +++ b/mysql-test/r/rpl_err_ignoredtable.result @@ -26,7 +26,7 @@ create table t2 (a int primary key); insert into t2 values(1); create table t3 (id int); insert into t3 values(connection_id()); - update t2 set a = a + 1 + get_lock('crash_lock%20C', 10); +update t2 set a = a + 1 + get_lock('crash_lock%20C', 10); select (@id := id) - id from t3; (@id := id) - id 0 diff --git a/mysql-test/r/rpl_master_pos_wait.result b/mysql-test/r/rpl_master_pos_wait.result index 81d9043c8ce..951e944fddc 100644 --- a/mysql-test/r/rpl_master_pos_wait.result +++ b/mysql-test/r/rpl_master_pos_wait.result @@ -12,7 +12,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1003 select master_pos_wait(_latin1'master-bin.999999',0,2) AS `master_pos_wait('master-bin.999999',0,2)` - select master_pos_wait('master-bin.999999',0); +select master_pos_wait('master-bin.999999',0); stop slave sql_thread; master_pos_wait('master-bin.999999',0) NULL diff --git a/mysql-test/r/rpl_ndb_sp003.result b/mysql-test/r/rpl_ndb_sp003.result index 94f320f387b..d7922c61b52 100644 --- a/mysql-test/r/rpl_ndb_sp003.result +++ b/mysql-test/r/rpl_ndb_sp003.result @@ -21,7 +21,7 @@ END| SELECT get_lock("test", 200); get_lock("test", 200) 1 - CALL test.p1(); +CALL test.p1(); CALL test.p2(); SELECT release_lock("test"); release_lock("test") diff --git a/mysql-test/r/rpl_row_sp003.result b/mysql-test/r/rpl_row_sp003.result index 01e352c3d46..df3e2a7ceed 100644 --- a/mysql-test/r/rpl_row_sp003.result +++ b/mysql-test/r/rpl_row_sp003.result @@ -21,7 +21,7 @@ END| SELECT get_lock("test", 200); get_lock("test", 200) 1 - CALL test.p1(); +CALL test.p1(); CALL test.p2(); SELECT release_lock("test"); release_lock("test") diff --git a/mysql-test/r/rpl_stm_000001.result b/mysql-test/r/rpl_stm_000001.result index ef4226e07b5..3b4cd05f640 100644 --- a/mysql-test/r/rpl_stm_000001.result +++ b/mysql-test/r/rpl_stm_000001.result @@ -44,7 +44,7 @@ create table t2(id int); insert into t2 values(connection_id()); create temporary table t3(n int); insert into t3 select get_lock('crash_lock%20C', 1) from t2; - update t1 set n = n + get_lock('crash_lock%20C', 2); +update t1 set n = n + get_lock('crash_lock%20C', 2); select (@id := id) - id from t2; (@id := id) - id 0 diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index b473bbac923..3836148faa9 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -672,7 +672,22 @@ SHOW TABLES FROM no_such_database; ERROR 42000: Unknown database 'no_such_database' SHOW COLUMNS FROM no_such_table; ERROR 42S02: Table 'test.no_such_table' doesn't exist -End of 5.0 tests. +flush status; +show status like 'slow_queries'; +Variable_name Value +Slow_queries 0 +show tables; +Tables_in_test +show status like 'slow_queries'; +Variable_name Value +Slow_queries 0 +select 1 from information_schema.tables limit 1; +1 +1 +show status like 'slow_queries'; +Variable_name Value +Slow_queries 1 +End of 5.0 tests SHOW AUTHORS; create database mysqltest; show create database mysqltest; diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result index c516d7a643f..953830ecc87 100644 --- a/mysql-test/r/sp-threads.result +++ b/mysql-test/r/sp-threads.result @@ -31,7 +31,7 @@ create procedure bug9486() update t1, t2 set val= 1 where id1=id2; call bug9486(); lock tables t2 write; - call bug9486(); +call bug9486(); show processlist; Id User Host db Command Time State Info # root localhost test Sleep # NULL @@ -77,7 +77,7 @@ select * from t1; end| use test; lock table t1 write; - call p2(); +call p2(); use test; drop procedure p1; create procedure p1() select * from t1; diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result index 564b8031c35..0b1fa565d28 100644 --- a/mysql-test/r/sp_notembedded.result +++ b/mysql-test/r/sp_notembedded.result @@ -74,8 +74,7 @@ flush status| flush query cache| delete from t1| drop procedure bug3583| -drop table t1; -#| +drop table t1| drop procedure if exists bug6807| create procedure bug6807() begin diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index a1463bc2b3c..8b41ba87423 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2717,8 +2717,7 @@ select (1,2,3) = (select * from t1); ERROR 21000: Operand should contain 3 column(s) select (select * from t1) = (1,2,3); ERROR 21000: Operand should contain 2 column(s) -drop table t1 -#; +drop table t1; CREATE TABLE `t1` ( `itemid` bigint(20) unsigned NOT NULL auto_increment, `sessionid` bigint(20) unsigned default NULL, diff --git a/mysql-test/r/synchronization.result b/mysql-test/r/synchronization.result index 697eb064998..4543a829494 100644 --- a/mysql-test/r/synchronization.result +++ b/mysql-test/r/synchronization.result @@ -1,6 +1,6 @@ drop table if exists t1; CREATE TABLE t1 (x1 int); - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -8,7 +8,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -16,7 +16,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -24,7 +24,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -32,7 +32,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -40,7 +40,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -48,7 +48,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -56,7 +56,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -64,7 +64,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -72,7 +72,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -80,7 +80,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -88,7 +88,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -96,7 +96,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -104,7 +104,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -112,7 +112,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -120,7 +120,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -128,7 +128,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -136,7 +136,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -144,7 +144,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -152,7 +152,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 53497fd528b..8382f521b84 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -215,6 +215,7 @@ select @@version; select @@global.version; @@global.version # +End of 4.1 tests set @first_var= NULL; create table t1 select @first_var; show create table t1; @@ -301,3 +302,11 @@ select @var; @var 3 drop table t1; +insert into city 'blah'; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''blah'' at line 1 +SHOW COUNT(*) WARNINGS; +@@session.warning_count +1 +SHOW COUNT(*) ERRORS; +@@session.error_count +1 diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 5ee3d64e56f..2e66c24d877 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -59,6 +59,7 @@ flush privileges; connect (con10,localhost,test,gambling2,); connect (con5,localhost,test,gambling2,mysql); +connection con5; set password=""; --error 1372 set password='gambling3'; diff --git a/mysql-test/t/crash_commit_before.test b/mysql-test/t/crash_commit_before.test index a10cf254a83..757817915dd 100644 --- a/mysql-test/t/crash_commit_before.test +++ b/mysql-test/t/crash_commit_before.test @@ -20,6 +20,9 @@ SET SESSION debug="d,crash_commit_before"; --error 2013 COMMIT; +# Turn on reconnect +--enable_reconnect + # Call script that will poll the server waiting for it to be back online again --source include/wait_until_connected_again.inc diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index f70b5b40766..82102a6078e 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1295,7 +1295,7 @@ SELECT fld3 FROM t2; # DROP TABLE t1; -ALTER TABLE t2 RENAME t1 +ALTER TABLE t2 RENAME t1; # # Drop and recreate diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 8c4a76c78a9..6af71e32cc4 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -9,29 +9,18 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -#events_bugs : BUG#17619 2006-02-21 andrey Race conditions -#events_stress : BUG#17619 2006-02-21 andrey Race conditions -#events : BUG#17619 2006-02-21 andrey Race conditions -#events_scheduling : BUG#19170 2006-04-26 andrey Test case of 19170 fails on some platforms. Has to be checked. im_options : Bug#20294 2006-07-24 stewart Instance manager test im_options fails randomly -#im_life_cycle : Bug#20368 2006-06-10 alik im_life_cycle test fails -im_daemon_life_cycle : BUG#22379 2006-09-15 ingo im_daemon_life_cycle.test fails on merge of 5.1 -> 5.1-engines -im_instance_conf : BUG#20294 2006-09-16 ingo Instance manager test im_instance_conf fails randomly concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random failures with varying differences ndb_autodiscover : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog ndb_autodiscover2 : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog -#ndb_binlog_ignore_db : BUG#21279 2006-07-25 ingo Randomly throws a warning ndb_load : BUG#17233 2006-05-04 tomas failed load data from infile causes mysqld dbug_assert, binlog not flushed partition_03ndb : BUG#16385 2006-03-24 mikael Partitions: crash when updating a range partitioned NDB table -ps : BUG#21524 2006-08-08 pgalbraith 'ps' test fails in --ps-protocol test AMD64 bit ps_7ndb : BUG#18950 2006-02-16 jmiller create table like does not obtain LOCK_open rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 Seems to pass currently -#rpl_ndb_commit_afterflush : BUG#19328 2006-05-04 tomas Slave timeout with COM_REGISTER_SLAVE error causing stop rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD rpl_ndb_ddl : BUG#18946 result file needs update + test needs to checked rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement -#rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly rpl_sp : BUG#16456 2006-02-16 jmiller @@ -39,8 +28,5 @@ rpl_multi_engine : BUG#22583 2006-09-23 lars # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open #ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second binlog may miss schema log events -#rpl_ndb_idempotent : BUG#21298 2006-07-27 msvensson -#rpl_row_basic_7ndb : BUG#21298 2006-07-27 msvensson -#rpl_truncate_7ndb : BUG#21298 2006-07-27 msvensson ndb_binlog_discover : bug#21806 2006-08-24 ndb_autodiscover3 : bug#21806 diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test index eeb5d509b94..68f07f258bf 100644 --- a/mysql-test/t/func_compress.test +++ b/mysql-test/t/func_compress.test @@ -56,7 +56,19 @@ insert into t1 values(NULL), (compress('a')); select uncompress(a), uncompressed_length(a) from t1; drop table t1; -# End of 4.1 tests +# +# Bug #23254: problem with compress(NULL) +# + +create table t1(a blob); +insert into t1 values ('0'), (NULL), ('0'); +--disable_result_log +select compress(a), compress(a) from t1; +--enable_result_log +select compress(a) is null from t1; +drop table t1; + +--echo End of 4.1 tests # # Bug #18539: uncompress(d) is null: impossible? diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test index e01fce30577..b575eeececa 100644 --- a/mysql-test/t/func_date_add.test +++ b/mysql-test/t/func_date_add.test @@ -64,4 +64,17 @@ insert into t1 values (date_add('2000-01-04', INTERVAL NULL DAY)); select * from t1; drop table t1; -# End of 4.1 tests +--echo End of 4.1 tests + +# +# Bug#21811 +# +# Make sure we end up with an appropriate +# date format (DATE) after addition operation +# +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 DAY; +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 MONTH; +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 YEAR; +SELECT CAST('2006-09-26' AS DATE) + INTERVAL 1 WEEK; + +--echo End of 5.0 tests diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index d49a4fed9d2..a0b0a929b6a 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -466,6 +466,47 @@ SET NAMES DEFAULT; # +# Bug #11655: Wrong time is returning from nested selects - maximum time exists +# +# check if SEC_TO_TIME() handles out-of-range values correctly +SELECT SEC_TO_TIME(3300000); +SELECT SEC_TO_TIME(3300000)+0; +SELECT SEC_TO_TIME(3600 * 4294967296); + +# check if TIME_TO_SEC() handles out-of-range values correctly +SELECT TIME_TO_SEC('916:40:00'); + +# check if ADDTIME() handles out-of-range values correctly +SELECT ADDTIME('500:00:00', '416:40:00'); +SELECT ADDTIME('916:40:00', '416:40:00'); + +# check if SUBTIME() handles out-of-range values correctly +SELECT SUBTIME('916:40:00', '416:40:00'); +SELECT SUBTIME('-916:40:00', '416:40:00'); + +# check if MAKETIME() handles out-of-range values correctly +SELECT MAKETIME(916,0,0); +SELECT MAKETIME(4294967296, 0, 0); +SELECT MAKETIME(-4294967296, 0, 0); +SELECT MAKETIME(0, 4294967296, 0); +SELECT MAKETIME(0, 0, 4294967296); +SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); + +# check if EXTRACT() handles out-of-range values correctly +SELECT EXTRACT(HOUR FROM '100000:02:03'); + +# check if we get proper warnings if both input string truncation +# and out-of-range value occur +CREATE TABLE t1(f1 TIME); +INSERT INTO t1 VALUES('916:00:00 a'); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #20927: sec_to_time treats big unsigned as signed +# +# check if SEC_TO_TIME() handles BIGINT UNSIGNED values correctly +SELECT SEC_TO_TIME(CAST(-1 AS UNSIGNED)); # Bug #19844 time_format in Union truncates values # diff --git a/mysql-test/t/im_daemon_life_cycle.imtest b/mysql-test/t/im_daemon_life_cycle.imtest index 55e52f4e464..5f8eb16a5d2 100644 --- a/mysql-test/t/im_daemon_life_cycle.imtest +++ b/mysql-test/t/im_daemon_life_cycle.imtest @@ -8,6 +8,9 @@ --source include/im_check_env.inc +# Turn on reconnect, not on by default anymore +--enable_reconnect + ########################################################################### # Kill the IM main process and check that the IM Angel will restart the main diff --git a/mysql-test/t/init_file.test b/mysql-test/t/init_file.test index 6b5e032fd99..31a6ef5a541 100644 --- a/mysql-test/t/init_file.test +++ b/mysql-test/t/init_file.test @@ -4,7 +4,7 @@ # # See mysql-test/std_data/init_file.dat and # mysql-test/t/init_file-master.opt for the actual test -# +# --echo ok --echo end of 4.1 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index f3296e6f706..6b2c84f880a 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -153,4 +153,21 @@ drop table t1; --exec echo "SELECT '\';';" >> $MYSQLTEST_VARDIR/tmp/bug20103.sql --exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug20103.sql 2>&1 +# +# Bug#17583: mysql drops connection when stdout is not writable +# +create table t17583 (a int); +insert into t17583 (a) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +# Close to the minimal data needed to exercise bug. +select count(*) from t17583; +--exec echo "select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; " |$MYSQL test >&- +drop table t17583; + --echo End of 5.0 tests diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 25f8d63d0b2..d98375ca746 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -317,7 +317,6 @@ select 3 from t1 ; # #select 3 from t1 ; -# End of 4.1 tests --error 1 --exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 @@ -360,18 +359,80 @@ select 3 from t1 ; # Missing delimiter # The comment will be "sucked into" the sleep command since # delimiter is missing until after "show status" ---system echo "sleep 4" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "# A comment" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "show status;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +sleep 4 +# A comment +show status; +EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 # # Missing delimiter until eof # The comment will be "sucked into" the sleep command since -# delimiter is missing ---system echo "sleep 7" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "# Another comment" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +# delimiter is missing +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +sleep 7 +# Another comment +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until "disable_query_log" +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default + +# +# comment +# comment 3 +disable_query_log; +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until "disable_query_log" +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default + +# +# comment + +# comment 3 +disable_query_log; +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until eof +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default + +# +# comment +# comment2 + +# comment 3 +--disable_query_log +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until eof +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default # comment +# comment part2 + +# comment 3 +--disable_query_log +EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 @@ -388,6 +449,67 @@ select 3 from t1 ; --sleep 1 # Wait for insert delayed to be executed. --sleep 1 # Wait for insert delayed to be executed. +# ---------------------------------------------------------------------------- +# Test error +# ---------------------------------------------------------------------------- + +# Missing argument +--error 1 +--exec echo "error;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error" | $MYSQL_TEST 2>&1 + +# First char must be uppercase 'S' or 'E' or [0-9] +--error 1 +--exec echo "--error s99999" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error e99999" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error 9eeeee" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error 1sssss" | $MYSQL_TEST 2>&1 + +# First char 'S' but too long +--error 1 +--exec echo "--error S999999" | $MYSQL_TEST 2>&1 + +# First char 'S' but lowercase char found +--error 1 +--exec echo "--error S99a99" | $MYSQL_TEST 2>&1 + +# First char 'S' but too short +--error 1 +--exec echo "--error S9999" | $MYSQL_TEST 2>&1 + +# First char 'E' but not found in error array +--error 1 +--exec echo "--error E9999" | $MYSQL_TEST 2>&1 + +# First char [0-9] but contains chars +--error 1 +--exec echo "--error 999e9" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error 9b" | $MYSQL_TEST 2>&1 + +# Multiple errorcodes separated by ',' +--error 1,1,1,1 +#--error 9,ER_PARSE_ERROR +#--error ER_PARSE_ERROR +#--error 9,ER_PARSE_ERROR,9,ER_PARSE_ERROR +#--error 9, ER_PARSE_ERROR, 9, ER_PARSE_ERROR +#--error 9,S00000,9,ER_PARSE_ERROR +#--error 9,S00000,9,ER_PARSE_ERROR,ER_PARSE_ERROR,ER_PARSE_ERROR,9,10,11,12 +--error 9,S00000,9 +--error 9,S00000,9,9,10,11,12 +--error 9 ,10 +--error 9 , 10 +--error 9 , 10 +--error 9 , 10 + +# Too many errorcodes specified +--error 1 +--exec echo "--error 1,2,3,4,5,6,7,8,9,10,11" | $MYSQL_TEST 2>&1 + # ---------------------------------------------------------------------------- # Test echo command @@ -610,6 +732,7 @@ echo $var3_var3; # Fix win paths --replace_result \\ / +# Source a nonexisting file --error 1 --exec echo "source non_existingFile;" | $MYSQL_TEST 2>&1 @@ -627,13 +750,16 @@ echo $var3_var3; # Test execution of source in a while loop +--write_file $MYSQLTEST_VARDIR/tmp/sourced.inc +echo here is the sourced script; +EOF --disable_query_log let $outer= 2; # Number of outer loops while ($outer) { eval SELECT '$outer = outer loop variable after while' AS ""; - --source include/sourced.inc + --source $MYSQLTEST_VARDIR/tmp/sourced.inc eval SELECT '$outer = outer loop variable before dec' AS ""; dec $outer; @@ -661,11 +787,12 @@ let $num= 9; while ($num) { SELECT 'In loop' AS ""; - --source include/sourced1.inc + --source $MYSQLTEST_VARDIR/tmp/sourced.inc dec $num; } --enable_abort_on_error --enable_query_log +--remove_file $MYSQLTEST_VARDIR/tmp/sourced.inc # ---------------------------------------------------------------------------- # Test sleep command @@ -817,10 +944,150 @@ while (!$i) } # Exceed max nesting level +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest_while.inc +let $1 = 10; +while ($1) +{ +while ($1) +{ +while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + echo $1; + dec $1; +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +EOF # Fix win path ---replace_result \\ / +--replace_result \\ / $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 ---exec echo "source include/mysqltest_while.inc;" | $MYSQL_TEST 2>&1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest_while.inc;" | $MYSQL_TEST 2>&1 +--remove_file $MYSQLTEST_VARDIR/tmp/mysqltest_while.inc --error 1 --exec echo "while \$i;" | $MYSQL_TEST 2>&1 --error 1 @@ -925,12 +1192,6 @@ select "a" as col1, "c" as col2; --error 1 --exec echo "connect (con2,);" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "connect (con2,localhost);" | $MYSQL_TEST 2>&1 ---error 1 ---exec echo "connect (con2, localhost, root);" | $MYSQL_TEST 2>&1 ---error 1 ---exec echo "connect (con2, localhost, root,);" | $MYSQL_TEST 2>&1 ---error 1 --exec echo "connect (con2,localhost,root,,illegal_db);" | $MYSQL_TEST 2>&1 --error 1 --exec echo "connect (con1,localhost,root,,,illegal_port,);" | $MYSQL_TEST 2>&1 @@ -938,13 +1199,15 @@ select "a" as col1, "c" as col2; --exec echo "connect (con1,localhost,root,,,,,SMTP POP);" | $MYSQL_TEST 2>&1 # Repeat connect/disconnect ---system echo "let \$i=100;" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "while (\$i)" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "{" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo " connect (test_con1,localhost,root,,); " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo " disconnect test_con1; " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo " dec \$i; " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "}" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +let $i=100; +while ($i) +{ + connect (test_con1,localhost,root,,); + disconnect test_con1; + dec $i; +} +EOF --exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql; echo OK;" | $MYSQL_TEST 2>&1 # Repeat connect/disconnect, exceed max number of connections @@ -1149,8 +1412,6 @@ query sleep; --error 1065 query ; ---echo End of 5.0 tests - # test for replace_regex --replace_regex /at/b/ select "at" as col1, "c" as col2; @@ -1189,4 +1450,103 @@ insert into t1 values (2,4); select * from t1; drop table t1; ---echo End of 5.1 tests +# ---------------------------------------------------------------------------- +# test for remove_file +# ---------------------------------------------------------------------------- + +--error 1 +--exec echo "remove_file ;" | $MYSQL_TEST 2>&1 + +--error 1 +remove_file non_existing_file; + +# ---------------------------------------------------------------------------- +# test for write_file +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "write_file ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "write_file filename ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "write_file filename \";" | $MYSQL_TEST 2>&1 + +write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +Content for test_file1 +EOF +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + +write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp END_DELIMITER; +Content for test_file1 contains EOF +END_DELIMITER +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + +# ---------------------------------------------------------------------------- +# test for file_exist +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "file_exists ;" | $MYSQL_TEST 2>&1 + +--error 0,1 +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +--error 1 +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +Content for test_file1 +EOF +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +--error 1 +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + + +# ---------------------------------------------------------------------------- +# test for copy_file +# ---------------------------------------------------------------------------- +--write_file $MYSQLTEST_VARDIR/tmp/file1.tmp +file1 +EOF + +copy_file $MYSQLTEST_VARDIR/tmp/file1.tmp $MYSQLTEST_VARDIR/tmp/file2.tmp; +file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/file2.tmp; + +--error 1 +--exec echo "copy_file ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "copy_file from_file;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# test for perl +# ---------------------------------------------------------------------------- +--perl +print "hello\n"; +EOF + +--perl EOF +print "hello\n"; +EOF + +--perl DELIMITER +print "hello\n"; +DELIMITER + +--error 1 +--exec echo "perl TOO_LONG_DELIMITER ;" | $MYSQL_TEST 2>&1 + +perl; +print "hello\n"; +EOF + +perl; + # Print "hello" + print "hello\n"; +EOF + + +--echo End of tests diff --git a/mysql-test/t/not_embedded_server-master.opt b/mysql-test/t/not_embedded_server-master.opt index 35fcc5f30c6..cef79bc8585 100644 --- a/mysql-test/t/not_embedded_server-master.opt +++ b/mysql-test/t/not_embedded_server-master.opt @@ -1 +1 @@ ---loose-to-force-a-restart +--force-restart diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 42fd0426d01..e66dcde71d2 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -4,6 +4,7 @@ # Taken fromm the select test # -- source include/have_partition.inc +-- source include/have_innodb.inc # # This test is disabled on Windows due to BUG#19107 # @@ -1286,37 +1287,51 @@ eval SET @inx_dir = 'INDEX DIRECTORY = ''$MYSQLTEST_VARDIR/master-data/tmpinx''' let $inx_directory = `select @inx_dir`; --enable_query_log ---replace_result $MYSQLTEST_VARDIR "hello" +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval create table t1 (a int) engine myisam partition by range (a) subpartition by hash (a) (partition p0 VALUES LESS THAN (1) $data_directory $inx_directory (SUBPARTITION subpart00, SUBPARTITION subpart01)); ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/test/t1.* || true ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/test/t1#* || true ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/tmpdata/t1#* || true ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/tmpinx/t1#* || true ---replace_result $MYSQLTEST_VARDIR "hello" - +--echo Checking if file exists before alter +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1.frm +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1.par +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p0#SP#subpart00.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p0#SP#subpart00.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p0#SP#subpart01.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p0#SP#subpart01.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/tmpdata/t1#P#p0#SP#subpart00.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/tmpdata/t1#P#p0#SP#subpart01.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/tmpinx/t1#P#p0#SP#subpart00.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/tmpinx/t1#P#p0#SP#subpart01.MYI + +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR eval ALTER TABLE t1 REORGANIZE PARTITION p0 INTO (partition p1 VALUES LESS THAN (1) $data_directory $inx_directory (SUBPARTITION subpart10, SUBPARTITION subpart11), partition p2 VALUES LESS THAN (2) $data_directory $inx_directory (SUBPARTITION subpart20, SUBPARTITION subpart21)); ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/test/t1.* || true ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/test/t1#* || true ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/tmpdata/t1#* || true ---replace_result $MYSQLTEST_VARDIR "hello" ---exec ls $MYSQLTEST_VARDIR/master-data/tmpinx/t1#* || true +--echo Checking if file exists after alter +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1.frm +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1.par +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p1#SP#subpart10.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p1#SP#subpart10.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p1#SP#subpart11.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p1#SP#subpart11.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p2#SP#subpart20.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p2#SP#subpart20.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p2#SP#subpart21.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/test/t1#P#p2#SP#subpart21.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/tmpdata/t1#P#p1#SP#subpart10.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/tmpdata/t1#P#p1#SP#subpart11.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/tmpdata/t1#P#p2#SP#subpart20.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/tmpdata/t1#P#p2#SP#subpart21.MYD +--file_exists $MYSQLTEST_VARDIR/master-data/tmpinx/t1#P#p1#SP#subpart10.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/tmpinx/t1#P#p1#SP#subpart11.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/tmpinx/t1#P#p2#SP#subpart20.MYI +--file_exists $MYSQLTEST_VARDIR/master-data/tmpinx/t1#P#p2#SP#subpart21.MYI drop table t1; --exec rmdir $MYSQLTEST_VARDIR/master-data/tmpdata || true diff --git a/mysql-test/t/ps-master.opt b/mysql-test/t/ps-master.opt new file mode 100644 index 00000000000..3eb98fc3d6b --- /dev/null +++ b/mysql-test/t/ps-master.opt @@ -0,0 +1 @@ +--log-slow-queries --log-long-format --log-queries-not-using-indexes diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index ac79dbc3434..62e2e9e8dd9 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -354,14 +354,14 @@ create table t1 (a int, b int); insert into t1 (a, b) values (1,1), (1,2), (2,1), (2,2); prepare stmt from "explain select * from t1 where t1.a=2 and t1.a=t1.b and t1.b > 1 + ?"; ---replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - set @v=5; -execute stmt using @v; --replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - -set @v=0; execute stmt using @v; +set @v=0; --replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - +execute stmt using @v; set @v=5; +--replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - execute stmt using @v; drop table t1; deallocate prepare stmt; @@ -1437,6 +1437,20 @@ DEALLOCATE PREPARE stmt; DROP TABLE t1, t2; +# +# Bug 19764: SHOW commands end up in the slow log as table scans +# + +flush status; +prepare sq from 'show status like "slow_queries"'; +execute sq; +prepare no_index from 'select 1 from information_schema.tables limit 1'; +execute sq; +execute no_index; +execute sq; +deallocate prepare no_index; +deallocate prepare sq; + --echo End of 5.0 tests. # @@ -1447,13 +1461,15 @@ create procedure proc_1() reset query cache; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin reset query cache; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; drop function func_1; +drop procedure proc_1; prepare abc from "reset query cache"; execute abc; execute abc; @@ -1462,13 +1478,15 @@ deallocate prepare abc; create procedure proc_1() reset master; -drop procedure proc_1; delimiter |; +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin reset master; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; drop function func_1; +drop procedure proc_1; prepare abc from "reset master"; execute abc; execute abc; @@ -1480,13 +1498,15 @@ create procedure proc_1() reset slave; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin reset slave; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; drop function func_1; +drop procedure proc_1; prepare abc from "reset slave"; execute abc; execute abc; @@ -1527,15 +1547,15 @@ call proc_1(); call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush hosts; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush hosts"; execute abc; execute abc; @@ -1547,15 +1567,15 @@ create procedure proc_1() flush privileges; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush privileges; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush privileges"; deallocate prepare abc; @@ -1567,11 +1587,15 @@ call proc_1(); unlock tables; call proc_1(); unlock tables; -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush tables with read lock; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG +select func_1(), func_1(), func_1() from dual; +drop function func_1; +drop procedure proc_1; prepare abc from "flush tables with read lock"; execute abc; execute abc; @@ -1584,15 +1608,15 @@ create procedure proc_1() flush tables; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush tables; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush tables"; execute abc; execute abc; @@ -1622,15 +1646,15 @@ select Host, User from mysql.user limit 0; select Host, Db from mysql.host limit 0; show open tables from mysql; flush tables; -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush tables; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; flush tables; select Host, User from mysql.user limit 0; select Host, Db from mysql.host limit 0; @@ -1659,15 +1683,15 @@ create procedure proc_1() flush logs; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush logs; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush logs"; execute abc; execute abc; @@ -1679,15 +1703,15 @@ create procedure proc_1() flush status; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush status; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush status"; execute abc; execute abc; @@ -1699,15 +1723,15 @@ create procedure proc_1() flush slave; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush slave; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush slave"; execute abc; execute abc; @@ -1716,15 +1740,15 @@ deallocate prepare abc; create procedure proc_1() flush master; -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush master; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush master"; deallocate prepare abc; @@ -1733,15 +1757,15 @@ create procedure proc_1() flush des_key_file; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush des_key_file; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush des_key_file"; execute abc; execute abc; @@ -1753,15 +1777,15 @@ create procedure proc_1() flush user_resources; call proc_1(); call proc_1(); call proc_1(); -drop procedure proc_1; delimiter |; --error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG create function func_1() returns int begin flush user_resources; return 1; end| +create function func_1() returns int begin call proc_1(); return 1; end| delimiter ;| ---error ER_SP_DOES_NOT_EXIST +--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST drop function func_1; +drop procedure proc_1; prepare abc from "flush user_resources"; execute abc; execute abc; @@ -1865,22 +1889,6 @@ execute abc; deallocate prepare abc; -create procedure proc_1() show scheduler status; -drop procedure proc_1; -delimiter |; ---error ER_SP_NO_RETSET -create function func_1() returns int begin show scheduler status; return 1; end| -delimiter ;| ---error ER_SP_DOES_NOT_EXIST -select func_1(), func_1(), func_1() from dual; ---error ER_SP_DOES_NOT_EXIST -drop function func_1; ---error ER_UNSUPPORTED_PS -prepare abc from "show scheduler status"; ---error ER_UNKNOWN_STMT_HANDLER -deallocate prepare abc; - - --disable_warnings drop procedure if exists a; --enable_warnings @@ -1997,10 +2005,13 @@ call proc_1(); call proc_1(); drop procedure proc_1; create procedure proc_1() install plugin my_plug soname 'some_plugin.so'; +--replace_regex /(Can\'t open shared library).*$/\1/ --error ER_CANT_OPEN_LIBRARY call proc_1(); +--replace_regex /(Can\'t open shared library).*$/\1/ --error ER_CANT_OPEN_LIBRARY call proc_1(); +--replace_regex /(Can\'t open shared library).*$/\1/ --error ER_CANT_OPEN_LIBRARY call proc_1(); drop procedure proc_1; @@ -2150,7 +2161,7 @@ drop event if exists xyz; #drop event xyz; #drop procedure proc_1; delimiter |; ---error ER_SP_NO_RETSET +--error ER_EVENT_RECURSIVITY_FORBIDDEN create function func_1() returns int begin create event xyz on schedule at now() do select 123; return 1; end| delimiter ;| --error ER_SP_DOES_NOT_EXIST diff --git a/mysql-test/t/ps_11bugs.test b/mysql-test/t/ps_11bugs.test index ff1c87f3bd8..515bcc03c1a 100644 --- a/mysql-test/t/ps_11bugs.test +++ b/mysql-test/t/ps_11bugs.test @@ -144,3 +144,37 @@ prepare st_18492 from 'select * from t1 where 3 in (select (1+1) union select 1) execute st_18492; drop table t1; + +# +# Bug#19356: Assertion failure with undefined @uservar in prepared statement execution +# +create table t1 (a int, b varchar(4)); +create table t2 (a int, b varchar(4), primary key(a)); + +prepare stmt1 from 'insert into t1 (a, b) values (?, ?)'; +prepare stmt2 from 'insert into t2 (a, b) values (?, ?)'; + +set @intarg= 11; +set @varchararg= '2222'; +execute stmt1 using @intarg, @varchararg; +execute stmt2 using @intarg, @varchararg; +set @intarg= 12; +execute stmt1 using @intarg, @UNDEFINED; +execute stmt2 using @intarg, @UNDEFINED; +set @intarg= 13; +execute stmt1 using @UNDEFINED, @varchararg; +--error 1048 +execute stmt2 using @UNDEFINED, @varchararg; +set @intarg= 14; +set @nullarg= Null; +execute stmt1 using @UNDEFINED, @nullarg; +--error 1048 +execute stmt2 using @nullarg, @varchararg; + +select * from t1; +select * from t2; + +drop table t1; +drop table t2; + +--echo End of 5.0 tests. diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index c0b81796731..4c0f411c758 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -316,8 +316,8 @@ prepare stmt4 from ' show table status from test like ''t9%'' '; --replace_column 8 # 12 # 13 # 14 # # Bug#4288 execute stmt4; ---replace_column 2 # prepare stmt4 from ' show status like ''Threads_running'' '; +--replace_column 2 # execute stmt4; prepare stmt4 from ' show variables like ''sql_mode'' '; execute stmt4; diff --git a/mysql-test/t/ps_grant.test b/mysql-test/t/ps_grant.test index 4c48b4d151f..b25facdb418 100644 --- a/mysql-test/t/ps_grant.test +++ b/mysql-test/t/ps_grant.test @@ -35,7 +35,7 @@ use mysqltest; --source include/ps_create.inc --source include/ps_renew.inc --enable_query_log -eval use $DB; +use test; grant usage on mysqltest.* to second_user@localhost identified by 'looser' ; grant select on mysqltest.t9 to second_user@localhost diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 2c94fe63c04..67c4c4cb20b 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -699,7 +699,7 @@ select a from t1; flush query cache; drop table t1, t2; -set GLOBAL query_cache_size=1355776 +set GLOBAL query_cache_size=1355776; # diff --git a/mysql-test/t/rpl_slave_status.test b/mysql-test/t/rpl_slave_status.test index a4a276b63d6..f98cc7a7d14 100644 --- a/mysql-test/t/rpl_slave_status.test +++ b/mysql-test/t/rpl_slave_status.test @@ -19,7 +19,7 @@ start slave; connection master; --disable_warnings drop table if exists t1; ---enable_warning +--enable_warnings create table t1 (n int); insert into t1 values (1); save_master_pos; diff --git a/mysql-test/t/rpl_truncate_7ndb.test b/mysql-test/t/rpl_truncate_7ndb.test index b0d4bdfc763..1d69eee5dd0 100644 --- a/mysql-test/t/rpl_truncate_7ndb.test +++ b/mysql-test/t/rpl_truncate_7ndb.test @@ -39,6 +39,7 @@ SELECT * FROM t1 ORDER BY a,b; --echo **** On Master **** connection master; DROP TABLE t1; +let SERVER_VERSION=`select version()`; --replace_regex /\/\* xid=[0-9]+ \*\//\/* xid= *\// /table_id: [0-9]+/table_id: #/ --replace_result $SERVER_VERSION SERVER_VERSION SHOW BINLOG EVENTS; diff --git a/mysql-test/t/show_check-master.opt b/mysql-test/t/show_check-master.opt new file mode 100644 index 00000000000..3eb98fc3d6b --- /dev/null +++ b/mysql-test/t/show_check-master.opt @@ -0,0 +1 @@ +--log-slow-queries --log-long-format --log-queries-not-using-indexes diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index 553b3d9059b..7d4ad099e6f 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -501,7 +501,19 @@ SHOW TABLES FROM no_such_database; --error ER_NO_SUCH_TABLE SHOW COLUMNS FROM no_such_table; -# End of 5.0 tests. + +# +# Bug #19764: SHOW commands end up in the slow log as table scans +# +flush status; +show status like 'slow_queries'; +show tables; +show status like 'slow_queries'; +# Table scan query, to ensure that slow_queries does still get incremented +# (mysqld is started with --log-queries-not-using-indexes) +select 1 from information_schema.tables limit 1; +show status like 'slow_queries'; + --echo End of 5.0 tests. --disable_result_log diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index e829a71c45a..2c85c6ae643 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -319,7 +319,7 @@ begin declare x int; end| ---error 1332 +--error 1332 create procedure p() begin declare c condition for 1064; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index b3563e21bdd..14c5bb00cee 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -2940,11 +2940,11 @@ begin end| --disable_parsing --replace_regex /table_id: [0-9]+/table_id: #/ -show binlog events; -show storage engines; -show master status; -show slave hosts; -show slave status; +show binlog events| +show storage engines| +show master status| +show slave hosts| +show slave status| --enable_parsing call bug4902()| diff --git a/mysql-test/t/sp_notembedded.test b/mysql-test/t/sp_notembedded.test index 28abf448089..6335ad55606 100644 --- a/mysql-test/t/sp_notembedded.test +++ b/mysql-test/t/sp_notembedded.test @@ -19,11 +19,11 @@ begin show grants for 'root'@'localhost'; end| --disable_parsing -show binlog events; -show storage engines; -show master status; -show slave hosts; -show slave status; +show binlog events| +show storage engines| +show master status| +show slave hosts| +show slave status| --enable_parsing call bug4902()| @@ -110,7 +110,7 @@ flush status| flush query cache| delete from t1| drop procedure bug3583| -drop table t1; +drop table t1| # # BUG#6807: Stored procedure crash if CREATE PROCEDURE ... KILL QUERY diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 7811301a9bc..d357b983703 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1728,7 +1728,7 @@ select (select a from t1) = (1,2); select (1,2,3) = (select * from t1); -- error 1241 select (select * from t1) = (1,2,3); -drop table t1 +drop table t1; # # Item_int_with_ref check (BUG#10020) diff --git a/mysql-test/t/system_mysql_db_fix.test b/mysql-test/t/system_mysql_db_fix.test index daba3b6ff86..3956e26e9cc 100644 --- a/mysql-test/t/system_mysql_db_fix.test +++ b/mysql-test/t/system_mysql_db_fix.test @@ -42,7 +42,7 @@ CREATE TABLE db ( KEY User (User) ) engine=MyISAM; ---enable-warnings +--enable_warnings INSERT INTO db VALUES ('%','test', '','Y','Y','Y','Y','Y','Y'); INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y'); @@ -60,7 +60,7 @@ CREATE TABLE host ( PRIMARY KEY Host (Host,Db) ) engine=MyISAM; ---enable-warnings +--enable_warnings --disable_warnings CREATE TABLE user ( @@ -79,7 +79,7 @@ CREATE TABLE user ( PRIMARY KEY Host (Host,User) ) engine=MyISAM; ---enable-warnings +--enable_warnings INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y'); INSERT INTO user VALUES ('localhost','', '','N','N','N','N','N','N','N','N','N'); diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 644ca506eba..65ca1b2c1b7 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -144,6 +144,8 @@ select @@version; --replace_column 1 # select @@global.version; +--echo End of 4.1 tests + # Bug #6598: problem with cast(NULL as signed integer); # @@ -210,4 +212,10 @@ select @var:=f2 from t1 group by f1 order by f2 desc limit 1; select @var; drop table t1; -# End of 4.1 tests +# +# Bug#19024 - SHOW COUNT(*) WARNINGS not return Errors +# +--error 1064 +insert into city 'blah'; +SHOW COUNT(*) WARNINGS; +SHOW COUNT(*) ERRORS; diff --git a/mysql-test/t/wait_timeout.test b/mysql-test/t/wait_timeout.test index dbd792e48d8..bdff72cdc76 100644 --- a/mysql-test/t/wait_timeout.test +++ b/mysql-test/t/wait_timeout.test @@ -55,7 +55,7 @@ select 2; select 3; # Disconnect so that we will not be confused by a future abort from this # connection. -disconnect default +disconnect default; # # Do the same test as above on a TCP connection diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 4aa99a70121..7b362b4c1f9 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -20,7 +20,7 @@ ADD_LIBRARY(mysys array.c charset-def.c charset.c checksum.c default.c default_m my_clock.c my_compress.c my_conio.c my_copy.c my_crc32.c my_create.c my_delete.c my_div.c my_error.c my_file.c my_fopen.c my_fstream.c my_gethostbyname.c my_gethwaddr.c my_getopt.c my_getsystime.c my_getwd.c my_handler.c my_init.c - my_lib.c my_lock.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c + my_lib.c my_lock.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index b209d64e78f..79d79d41c34 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -43,7 +43,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ tree.c trie.c list.c hash.c array.c string.c typelib.c \ my_copy.c my_append.c my_lib.c \ my_delete.c my_rename.c my_redel.c \ - my_chsize.c my_lread.c my_lwrite.c my_clock.c \ + my_chsize.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ my_sync.c my_getopt.c my_mkdir.c \ default_modify.c default.c \ diff --git a/mysys/charset.c b/mysys/charset.c index 64b15fab0c2..d10a580ae4e 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -312,7 +312,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) { char *buf; int fd; - uint len; + uint len, tmp_len; MY_STAT stat_info; if (!my_stat(filename, &stat_info, MYF(myflags)) || @@ -321,12 +321,11 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) return TRUE; if ((fd=my_open(filename,O_RDONLY,myflags)) < 0) - { - my_free(buf,myflags); - return TRUE; - } - len=read(fd,buf,len); + goto error; + tmp_len=my_read(fd, buf, len, myflags); my_close(fd,myflags); + if (tmp_len != len) + goto error; if (my_parse_charset_xml(buf,len,add_collation)) { @@ -340,6 +339,10 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) my_free(buf, myflags); return FALSE; + +error: + my_free(buf, myflags); + return TRUE; } diff --git a/mysys/make-ccc b/mysys/make-ccc index 9c54185682a..b34bd80e1d1 100755 --- a/mysys/make-ccc +++ b/mysys/make-ccc @@ -1,4 +1,4 @@ rm -f .deps/* raid.o mf_iocache.o libmysys.a -ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c +ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c make raid.o mf_iocache.o my_lock.o ar -cr libmysys.a array.o raid.o mf_iocache.o my_lock.o diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index cd2a140182e..eb8b992c601 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -333,7 +333,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, { info->read_end=info->write_pos; info->end_of_file=my_b_tell(info); - info->seek_not_done=1; + /* + Trigger a new seek only if we have a valid + file handle. + */ + info->seek_not_done= (info->file != -1); } else if (type == WRITE_CACHE) { diff --git a/mysys/my_lread.c b/mysys/my_lread.c deleted file mode 100644 index 601d772b844..00000000000 --- a/mysys/my_lread.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "mysys_priv.h" -#include "mysys_err.h" - - /* Read a chunk of bytes from a file */ - -uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags) - /* File descriptor */ - /* Buffer must be at least count bytes */ - /* Max number of bytes returnd */ - /* Flags on what to do on error */ -{ - uint32 readbytes; - DBUG_ENTER("my_lread"); - DBUG_PRINT("my",("Fd: %d Buffer: %ld Count: %ld MyFlags: %d", - Filedes, Buffer, Count, MyFlags)); - - /* Temp hack to get count to int32 while read wants int */ - if ((readbytes = (uint32) read(Filedes, Buffer, (uint) Count)) != Count) - { - my_errno=errno; - if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) - { - if (readbytes == MY_FILE_ERROR) - my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),errno); - else - if (MyFlags & (MY_NABP | MY_FNABP)) - my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),errno); - } - if (readbytes == MY_FILE_ERROR || MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN((uint32) -1); /* Return med felkod */ - } - if (MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN(0); /* Ok vid l{sning */ - DBUG_RETURN(readbytes); -} /* my_lread */ diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c deleted file mode 100644 index 3b9afdbd71f..00000000000 --- a/mysys/my_lwrite.c +++ /dev/null @@ -1,46 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#include "mysys_priv.h" -#include "mysys_err.h" - - /* Write a chunk of bytes to a file */ - -uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags) -{ - uint32 writenbytes; - DBUG_ENTER("my_lwrite"); - DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %ld MyFlags: %d", - Filedes, Buffer, Count, MyFlags)); - - /* Temp hack to get count to int32 while write wants int */ - if ((writenbytes = (uint32) write(Filedes, Buffer, (uint) Count)) != Count) - { - my_errno=errno; - if (writenbytes == (uint32) -1 || MyFlags & (MY_NABP | MY_FNABP)) - { - if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) - { - my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG), - my_filename(Filedes),errno); - } - DBUG_RETURN((uint32) -1); /* Return med felkod */ - } - } - if (MyFlags & (MY_NABP | MY_FNABP)) - DBUG_RETURN(0); /* Ok vid l{sning */ - DBUG_RETURN(writenbytes); -} /* my_lwrite */ diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 978366e57e5..45a4a363c0a 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -75,8 +75,12 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d", readbytes,Count,Filedes,my_errno)); #ifdef THREAD - if (readbytes == 0 && errno == EINTR) - continue; /* Interrupted */ + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d", + (int) readbytes)); + continue; /* Interrupted */ + } #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { @@ -170,8 +174,8 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } - if ((writenbytes == 0 && my_errno == EINTR) || - (writenbytes > 0 && (uint) writenbytes != (uint) -1)) + if ((writenbytes > 0 && (uint) writenbytes != (uint) -1) || + my_errno == EINTR) continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) diff --git a/mysys/my_quick.c b/mysys/my_quick.c index 44ed3fc0b2c..ffc8160c371 100644 --- a/mysys/my_quick.c +++ b/mysys/my_quick.c @@ -26,6 +26,14 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags) if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count) { +#ifndef DBUG_OFF + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("error", ("my_quick_read() was interrupted and returned %d" + ". This function does not retry the read!", + (int) readbytes)); + } +#endif my_errno=errno; return readbytes; } @@ -35,8 +43,24 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags) uint my_quick_write(File Filedes,const byte *Buffer,uint Count) { - if ((uint) write(Filedes,Buffer,Count) != Count) +#ifndef DBUG_OFF + uint writtenbytes; +#endif + + if (( +#ifndef DBUG_OFF + writtenbytes = +#endif + (uint) write(Filedes,Buffer,Count)) != Count) { +#ifndef DBUG_OFF + if ((writtenbytes == 0 || (int) writtenbytes == -1) && errno == EINTR) + { + DBUG_PRINT("error", ("my_quick_write() was interrupted and returned %d" + ". This function does not retry the write!", + (int) writtenbytes)); + } +#endif my_errno=errno; return (uint) -1; } diff --git a/mysys/my_read.c b/mysys/my_read.c index 2e23f2175f8..8b88e483fef 100644 --- a/mysys/my_read.c +++ b/mysys/my_read.c @@ -51,10 +51,11 @@ uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags) DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d", readbytes, Count, Filedes, my_errno)); #ifdef THREAD - if ((int) readbytes <= 0 && errno == EINTR) - { - DBUG_PRINT("debug", ("my_read() was interrupted and returned %d", (int) readbytes)); - continue; /* Interrupted */ + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("debug", ("my_read() was interrupted and returned %d", + (int) readbytes)); + continue; /* Interrupted */ } #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) diff --git a/mysys/my_seek.c b/mysys/my_seek.c index e5b1905e551..239136c4e7c 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -29,8 +29,13 @@ my_off_t my_seek(File fd, my_off_t pos, int whence, whence, MyFlags)); DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */ - if (-1 != fd) - newpos=lseek(fd, pos, whence); + /* + Make sure we are using a valid file descriptor! + */ + DBUG_ASSERT(fd != -1); + + newpos= lseek(fd, pos, whence); + if (newpos == (os_off_t) -1) { my_errno=errno; diff --git a/mysys/my_write.c b/mysys/my_write.c index 4e8369480b3..ae8cb4ab02b 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -57,18 +57,24 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } - if (!writenbytes) + + if ((writenbytes == 0 || (int) writenbytes == -1)) { - /* We may come here on an interrupt or if the file quote is exeeded */ if (my_errno == EINTR) - continue; - if (!errors++) /* Retry once */ { - errno=EFBIG; /* Assume this is the error */ - continue; + DBUG_PRINT("debug", ("my_write() was interrupted and returned %d", + (int) writenbytes)); + continue; /* Interrupted */ + } + + if (!writenbytes && !errors++) /* Retry once */ + { + /* We may come here if the file quota is exeeded */ + errno=EFBIG; /* Assume this is the error */ + continue; } } - else if ((uint) writenbytes != (uint) -1) + else continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) diff --git a/netware/BUILD/compile-netware-max b/netware/BUILD/compile-netware-max index ec737d4615c..d8278a4e915 100644..100755 --- a/netware/BUILD/compile-netware-max +++ b/netware/BUILD/compile-netware-max @@ -15,7 +15,7 @@ suffix="max" extra_configs=" \ --with-innodb \ --with-embedded-server \ - --with-openssl \ + --with-ssl \ " . $path/compile-netware-END diff --git a/netware/BUILD/compile-netware-max-debug b/netware/BUILD/compile-netware-max-debug index ea3553ae6e1..de1b5dd17cc 100644..100755 --- a/netware/BUILD/compile-netware-max-debug +++ b/netware/BUILD/compile-netware-max-debug @@ -15,7 +15,7 @@ extra_configs=" \ --with-innodb \ --with-debug=full \ --with-embedded-server \ - --with-openssl \ + --with-ssl \ " . $path/compile-netware-END diff --git a/netware/BUILD/compile-netware-src b/netware/BUILD/compile-netware-src index f4e8a53ffea..f4e8a53ffea 100644..100755 --- a/netware/BUILD/compile-netware-src +++ b/netware/BUILD/compile-netware-src diff --git a/netware/BUILD/mwenv b/netware/BUILD/mwenv index d8d53293b2c..c3869d2ec90 100755 --- a/netware/BUILD/mwenv +++ b/netware/BUILD/mwenv @@ -26,8 +26,17 @@ WINE_BUILD_DIR=`echo "$BUILD_DIR" | sed 's_'$base_unix_part'/__'` WINE_BUILD_DIR="$base/$WINE_BUILD_DIR" echo "WINE_BUILD_DIR: $WINE_BUILD_DIR" -export MWCNWx86Includes="$MYDEV/libc/include;$MYDEV/fs64/headers;$MYDEV/zlib-1.2.3;$WINE_BUILD_DIR/include;$MYDEV" -export MWNWx86Libraries="$MYDEV/libc/imports;$MYDEV/mw/lib;$MYDEV/fs64/imports;$MYDEV/zlib-1.2.3;$MYDEV/openssl;$WINE_BUILD_DIR/netware/BUILD" +# Look for libc, MySQL 5.1.x uses libc-2006 by default +libcdir="$MYDEV/libc-2006" +if test ! -d $libcdir +then + # The libcdir didn't exist, set default + libc_dir="$MYDEV/libc" +fi +echo "Using libc in $libc_dir"; + +export MWCNWx86Includes="$libc_dir/include;$MYDEV/fs64/headers;$MYDEV/zlib-1.2.3;$WINE_BUILD_DIR/include;$MYDEV" +export MWNWx86Libraries="$libc_dir/imports;$MYDEV/mw/lib;$MYDEV/fs64/imports;$MYDEV/zlib-1.2.3;$MYDEV/openssl;$WINE_BUILD_DIR/netware/BUILD" export MWNWx86LibraryFiles="libcpre.o;libc.imp;netware.imp;mwcrtl.lib;mwcpp.lib;libz.a;neb.imp;zPublics.imp;knetware.imp" export WINEPATH="$MYDEV/mw/bin" @@ -46,3 +55,15 @@ export LD='mwldnlm' export LDFLAGS='-entry _LibCPrelude -exit _LibCPostlude -map -flags pseudopreemption' export RANLIB=: export STRIP=: + +# +# Check that TERM has been set to avoid problem "Error opening +# terminal: unknown" when the script is executed using non interactive ssh +# +if test -z "$TERM" -o "$TERM"=dumb +then + export TERM=linux +fi + +# Print all env. variables +export diff --git a/sql-common/client.c b/sql-common/client.c index 79a5be938b2..b6947028e74 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2364,6 +2364,8 @@ my_bool mysql_reconnect(MYSQL *mysql) { MYSQL tmp_mysql; DBUG_ENTER("mysql_reconnect"); + DBUG_ASSERT(mysql); + DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect)); if (!mysql->reconnect || (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) diff --git a/sql-common/my_time.c b/sql-common/my_time.c index b4cfe041529..29de0504468 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -465,8 +465,10 @@ err: There may be an optional [.second_part] after seconds length Length of str l_time Store result here - was_cut Set to 1 if value was cut during conversion or to 0 - otherwise. + warning Set MYSQL_TIME_WARN_TRUNCATED flag if the input string + was cut during conversion, and/or + MYSQL_TIME_WARN_OUT_OF_RANGE flag, if the value is + out of range. NOTES Because of the extra days argument, this function can only @@ -478,15 +480,16 @@ err: */ my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, - int *was_cut) + int *warning) { - long date[5],value; + ulong date[5]; + ulonglong value; const char *end=str+length, *end_of_days; my_bool found_days,found_hours; uint state; l_time->neg=0; - *was_cut= 0; + *warning= 0; for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') @@ -501,13 +504,16 @@ my_bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, /* Check first if this is a full TIMESTAMP */ if (length >= 12) { /* Probably full timestamp */ + int was_cut; enum enum_mysql_timestamp_type res= str_to_datetime(str, length, l_time, - (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), was_cut); + (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut); if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR) + { + if (was_cut) + *warning|= MYSQL_TIME_WARN_TRUNCATED; return res == MYSQL_TIMESTAMP_ERROR; - /* We need to restore was_cut flag since str_to_datetime can modify it */ - *was_cut= 0; + } } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ @@ -587,7 +593,7 @@ fractional: if (field_length > 0) value*= (long) log_10_int[field_length]; else if (field_length < 0) - *was_cut= 1; + *warning|= MYSQL_TIME_WARN_TRUNCATED; date[4]=value; } else @@ -601,10 +607,7 @@ fractional: ((str[1] == '-' || str[1] == '+') && (end - str) > 2 && my_isdigit(&my_charset_latin1, str[2])))) - { - *was_cut= 1; return 1; - } if (internal_format_positions[7] != 255) { @@ -623,12 +626,12 @@ fractional: } } - /* Some simple checks */ - if (date[2] >= 60 || date[3] >= 60) - { - *was_cut= 1; + /* Integer overflow checks */ + if (date[0] > UINT_MAX || date[1] > UINT_MAX || + date[2] > UINT_MAX || date[3] > UINT_MAX || + date[4] > UINT_MAX) return 1; - } + l_time->year= 0; /* For protocol::store_time */ l_time->month= 0; l_time->day= date[0]; @@ -638,6 +641,10 @@ fractional: l_time->second_part= date[4]; l_time->time_type= MYSQL_TIMESTAMP_TIME; + /* Check if the value is valid and fits into TIME range */ + if (check_time_range(l_time, warning)) + return 1; + /* Check if there is garbage at end of the TIME specification */ if (str != end) { @@ -645,7 +652,7 @@ fractional: { if (!my_isspace(&my_charset_latin1,*str)) { - *was_cut= 1; + *warning|= MYSQL_TIME_WARN_TRUNCATED; break; } } while (++str != end); @@ -655,6 +662,47 @@ fractional: /* + Check 'time' value to lie in the TIME range + + SYNOPSIS: + check_time_range() + time pointer to TIME value + warning set MYSQL_TIME_WARN_OUT_OF_RANGE flag if the value is out of range + + DESCRIPTION + If the time value lies outside of the range [-838:59:59, 838:59:59], + set it to the closest endpoint of the range and set + MYSQL_TIME_WARN_OUT_OF_RANGE flag in the 'warning' variable. + + RETURN + 0 time value is valid, but was possibly truncated + 1 time value is invalid +*/ + +int check_time_range(struct st_mysql_time *time, int *warning) +{ + longlong hour; + + if (time->minute >= 60 || time->second >= 60) + return 1; + + hour= time->hour + (24*time->day); + if (hour <= TIME_MAX_HOUR && + (hour != TIME_MAX_HOUR || time->minute != TIME_MAX_MINUTE || + time->second != TIME_MAX_SECOND || !time->second_part)) + return 0; + + time->day= 0; + time->hour= TIME_MAX_HOUR; + time->minute= TIME_MAX_MINUTE; + time->second= TIME_MAX_SECOND; + time->second_part= 0; + *warning|= MYSQL_TIME_WARN_OUT_OF_RANGE; + return 0; +} + + +/* Prepare offset of system time zone from UTC for my_system_gmt_sec() func. SYNOPSIS @@ -840,7 +888,7 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type) int my_time_to_str(const MYSQL_TIME *l_time, char *to) { uint extra_hours= 0; - return my_sprintf(to, (to, "%s%02d:%02d:%02d", + return my_sprintf(to, (to, "%s%02u:%02u:%02u", (l_time->neg ? "-" : ""), extra_hours+ l_time->hour, l_time->minute, @@ -849,7 +897,7 @@ int my_time_to_str(const MYSQL_TIME *l_time, char *to) int my_date_to_str(const MYSQL_TIME *l_time, char *to) { - return my_sprintf(to, (to, "%04d-%02d-%02d", + return my_sprintf(to, (to, "%04u-%02u-%02u", l_time->year, l_time->month, l_time->day)); @@ -857,7 +905,7 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to) int my_datetime_to_str(const MYSQL_TIME *l_time, char *to) { - return my_sprintf(to, (to, "%04d-%02d-%02d %02d:%02d:%02d", + return my_sprintf(to, (to, "%04u-%02u-%02u %02u:%02u:%02u", l_time->year, l_time->month, l_time->day, diff --git a/sql/field.cc b/sql/field.cc index 09e919d872a..122a44305f2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4875,9 +4875,10 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) { TIME ltime; long tmp; - int error; + int error= 0; + int warning; - if (str_to_time(from, len, <ime, &error)) + if (str_to_time(from, len, <ime, &warning)) { tmp=0L; error= 2; @@ -4886,29 +4887,27 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) } else { - if (error) + if (warning & MYSQL_TIME_WARN_TRUNCATED) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, from, len, MYSQL_TIMESTAMP_TIME, 1); - - if (ltime.month) - ltime.day=0; - tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second); - if (tmp > 8385959) + if (warning & MYSQL_TIME_WARN_OUT_OF_RANGE) { - tmp=8385959; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, from, len, MYSQL_TIMESTAMP_TIME, !error); error= 1; } + if (ltime.month) + ltime.day=0; + tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second); if (error > 1) error= 2; } if (ltime.neg) tmp= -tmp; - error |= Field_time::store((longlong) tmp, FALSE); + int3store(ptr,tmp); return error; } @@ -4928,16 +4927,16 @@ int Field_time::store(double nr) ASSERT_COLUMN_MARKED_FOR_WRITE; long tmp; int error= 0; - if (nr > 8385959.0) + if (nr > (double)TIME_MAX_VALUE) { - tmp=8385959L; + tmp= TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME); error= 1; } - else if (nr < -8385959.0) + else if (nr < (double)-TIME_MAX_VALUE) { - tmp= -8385959L; + tmp= -TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME); error= 1; @@ -4966,17 +4965,17 @@ int Field_time::store(longlong nr, bool unsigned_val) ASSERT_COLUMN_MARKED_FOR_WRITE; long tmp; int error= 0; - if (nr < (longlong) -8385959L && !unsigned_val) + if (nr < (longlong) -TIME_MAX_VALUE && !unsigned_val) { - tmp= -8385959L; + tmp= -TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); error= 1; } - else if (nr > (longlong) 8385959 || nr < 0 && unsigned_val) + else if (nr > (longlong) TIME_MAX_VALUE || nr < 0 && unsigned_val) { - tmp=8385959L; + tmp= TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7a82dd753b3..bf837f6720b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2965,6 +2965,7 @@ String *Item_func_compress::val_str(String *str) null_value= 1; return 0; } + null_value= 0; if (res->is_empty()) return res; /* diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d32adde5e64..f378e5037dc 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -96,6 +96,125 @@ static bool make_datetime(date_time_format_types format, TIME *ltime, /* + Wrapper over make_datetime() with validation of the input TIME value + + NOTE + see make_datetime() for more information + + RETURN + 1 if there was an error during converion + 0 otherwise +*/ + +static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime, + String *str) +{ + int warning= 0; + bool rc; + + if (make_datetime(format, ltime, str)) + return 1; + if (check_time_range(ltime, &warning)) + return 1; + if (!warning) + return 0; + + make_truncated_value_warning(current_thd, str->ptr(), str->length(), + MYSQL_TIMESTAMP_TIME, NullS); + return make_datetime(format, ltime, str); +} + + +/* + Wrapper over make_time() with validation of the input TIME value + + NOTE + see make_time() for more info + + RETURN + 1 if there was an error during conversion + 0 otherwise +*/ + +static bool make_time_with_warn(const DATE_TIME_FORMAT *format, + TIME *l_time, String *str) +{ + int warning= 0; + make_time(format, l_time, str); + if (check_time_range(l_time, &warning)) + return 1; + if (warning) + { + make_truncated_value_warning(current_thd, str->ptr(), str->length(), + MYSQL_TIMESTAMP_TIME, NullS); + make_time(format, l_time, str); + } + + return 0; +} + + +/* + Convert seconds to TIME value with overflow checking + + SYNOPSIS: + sec_to_time() + seconds number of seconds + unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise + ltime output TIME value + + DESCRIPTION + If the 'seconds' argument is inside TIME data range, convert it to a + corresponding value. + Otherwise, truncate the resulting value to the nearest endpoint, and + produce a warning message. + + RETURN + 1 if the value was truncated during conversion + 0 otherwise +*/ + +static bool sec_to_time(longlong seconds, bool unsigned_flag, TIME *ltime) +{ + uint sec; + + bzero((char *)ltime, sizeof(*ltime)); + + if (seconds < 0) + { + if (unsigned_flag) + goto overflow; + ltime->neg= 1; + if (seconds < -3020399) + goto overflow; + seconds= -seconds; + } + else if (seconds > 3020399) + goto overflow; + + sec= (uint) ((ulonglong) seconds % 3600); + ltime->hour= (uint) (seconds/3600); + ltime->minute= sec/60; + ltime->second= sec % 60; + + return 0; + +overflow: + ltime->hour= TIME_MAX_HOUR; + ltime->minute= TIME_MAX_MINUTE; + ltime->second= TIME_MAX_SECOND; + + char buf[22]; + int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10) + - buf); + make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME, + NullS); + + return 1; +} + + +/* Date formats corresponding to compound %r and %T conversion specifiers Note: We should init at least first element of "positions" array @@ -1546,8 +1665,6 @@ int Item_func_sysdate_local::save_in_field(Field *to, bool no_conversions) String *Item_func_sec_to_time::val_str(String *str) { DBUG_ASSERT(fixed == 1); - longlong seconds=(longlong) args[0]->val_int(); - uint sec; TIME ltime; if ((null_value=args[0]->null_value) || str->alloc(19)) @@ -1556,19 +1673,8 @@ String *Item_func_sec_to_time::val_str(String *str) return (String*) 0; } - ltime.neg= 0; - if (seconds < 0) - { - seconds= -seconds; - ltime.neg= 1; - } - - sec= (uint) ((ulonglong) seconds % 3600); - ltime.day= 0; - ltime.hour= (uint) (seconds/3600); - ltime.minute= sec/60; - ltime.second= sec % 60; - + sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; } @@ -1577,16 +1683,15 @@ String *Item_func_sec_to_time::val_str(String *str) longlong Item_func_sec_to_time::val_int() { DBUG_ASSERT(fixed == 1); - longlong seconds=args[0]->val_int(); - longlong sign=1; + TIME ltime; + if ((null_value=args[0]->null_value)) return 0; - if (seconds < 0) - { - seconds= -seconds; - sign= -1; - } - return sign*((seconds / 3600)*10000+((seconds/60) % 60)*100+ (seconds % 60)); + + sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + + return (ltime.neg ? -1 : 1) * + ((ltime.hour)*10000 + ltime.minute*100 + ltime.second); } @@ -2030,11 +2135,15 @@ bool Item_date_add_interval::eq(const Item *item, bool binary_cmp) const (date_sub_interval == other->date_sub_interval)); } +/* + 'interval_names' reflects the order of the enumeration interval_type. + See item_timefunc.h + */ static const char *interval_names[]= { - "year", "quarter", "month", "day", "hour", - "minute", "week", "second", "microsecond", + "year", "quarter", "month", "week", "day", + "hour", "minute", "second", "microsecond", "year_month", "day_hour", "day_minute", "day_second", "hour_minute", "hour_second", "minute_second", "day_microsecond", @@ -2571,7 +2680,9 @@ String *Item_func_add_time::val_str(String *str) } if (l_time1.neg != l_time2.neg) l_sign= -l_sign; - + + bzero((char *)&l_time3, sizeof(l_time3)); + l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign, &seconds, µseconds); @@ -2600,9 +2711,9 @@ String *Item_func_add_time::val_str(String *str) } l_time3.hour+= days*24; - if (!make_datetime(l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY, - &l_time3, str)) + if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2657,6 +2768,8 @@ String *Item_func_timediff::val_str(String *str) if (l_time1.neg != l_time2.neg) l_sign= -l_sign; + bzero((char *)&l_time3, sizeof(l_time3)); + l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign, &seconds, µseconds); @@ -2670,9 +2783,9 @@ String *Item_func_timediff::val_str(String *str) calc_time_from_sec(&l_time3, (long) seconds, microseconds); - if (!make_datetime(l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY, - &l_time3, str)) + if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2690,29 +2803,58 @@ String *Item_func_maketime::val_str(String *str) { DBUG_ASSERT(fixed == 1); TIME ltime; + bool overflow= 0; - long hour= (long) args[0]->val_int(); - long minute= (long) args[1]->val_int(); - long second= (long) args[2]->val_int(); + longlong hour= args[0]->val_int(); + longlong minute= args[1]->val_int(); + longlong second= args[2]->val_int(); if ((null_value=(args[0]->null_value || - args[1]->null_value || - args[2]->null_value || - minute > 59 || minute < 0 || - second > 59 || second < 0 || - str->alloc(19)))) + args[1]->null_value || + args[2]->null_value || + minute < 0 || minute > 59 || + second < 0 || second > 59 || + str->alloc(19)))) return 0; + bzero((char *)<ime, sizeof(ltime)); ltime.neg= 0; + + /* Check for integer overflows */ if (hour < 0) { - ltime.neg= 1; - hour= -hour; + if (args[0]->unsigned_flag) + overflow= 1; + else + ltime.neg= 1; + } + if (-hour > UINT_MAX || hour > UINT_MAX) + overflow= 1; + + if (!overflow) + { + ltime.hour= (uint) ((hour < 0 ? -hour : hour)); + ltime.minute= (uint) minute; + ltime.second= (uint) second; + } + else + { + ltime.hour= TIME_MAX_HOUR; + ltime.minute= TIME_MAX_MINUTE; + ltime.second= TIME_MAX_SECOND; + char buf[28]; + char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10); + int len = (int)(ptr - buf) + + my_sprintf(ptr, (ptr, ":%02u:%02u", (uint)minute, (uint)second)); + make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME, + NullS); + } + + if (make_time_with_warn((DATE_TIME_FORMAT *) 0, <ime, str)) + { + null_value= 1; + return 0; } - ltime.hour= (ulong) hour; - ltime.minute= (ulong) minute; - ltime.second= (ulong) second; - make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; } @@ -3056,7 +3198,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) goto null_date; null_value= 0; - bzero((char*) ltime, sizeof(ltime)); + bzero((char*) ltime, sizeof(*ltime)); date_time_format.format.str= (char*) format->ptr(); date_time_format.format.length= format->length(); if (extract_date_time(&date_time_format, val->ptr(), val->length(), diff --git a/sql/set_var.cc b/sql/set_var.cc index 4369c288cd5..8769ca6c1cb 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3141,6 +3141,7 @@ static byte *get_warning_count(THD *thd) { thd->sys_var_tmp.long_value= (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] + + thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] + thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]); return (byte*) &thd->sys_var_tmp.long_value; } diff --git a/sql/sp.cc b/sql/sp.cc index 3411a18c17a..fd42ec8e9f2 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -653,6 +653,17 @@ db_drop_routine(THD *thd, int type, sp_name *name) if (table->file->ha_delete_row(table->record[0])) ret= SP_DELETE_ROW_FAILED; } + + if (ret == SP_OK) + { + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + } + close_thread_tables(thd); DBUG_RETURN(ret); } @@ -687,6 +698,17 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if ((table->file->ha_update_row(table->record[1],table->record[0]))) ret= SP_WRITE_ROW_FAILED; } + + if (ret == SP_OK) + { + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + } + close_thread_tables(thd); DBUG_RETURN(ret); } @@ -765,6 +787,7 @@ print_field_values(THD *thd, TABLE *table, return SP_INTERNAL_ERROR; } } + return SP_OK; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c55fc744cd0..aa13c2f08f4 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3140,9 +3140,22 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, grant_option=TRUE; thd->mem_root= old_root; pthread_mutex_unlock(&acl_cache->lock); + + if (!result) /* success */ + { + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + } + rw_unlock(&LOCK_grant); - if (!result) + + if (!result) /* success */ send_ok(thd); + /* Tables are automatically closed */ DBUG_RETURN(result); } @@ -3294,9 +3307,21 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, grant_option=TRUE; thd->mem_root= old_root; pthread_mutex_unlock(&acl_cache->lock); + if (!result && !no_error) + { + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + } + rw_unlock(&LOCK_grant); + if (!result && !no_error) send_ok(thd); + /* Tables are automatically closed */ DBUG_RETURN(result); } @@ -3394,11 +3419,23 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, } } VOID(pthread_mutex_unlock(&acl_cache->lock)); + + if (!result) + { + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + } + rw_unlock(&LOCK_grant); close_thread_tables(thd); if (!result) send_ok(thd); + DBUG_RETURN(result); } @@ -5398,6 +5435,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) } VOID(pthread_mutex_unlock(&acl_cache->lock)); + + if (mysql_bin_log.is_open()) + { + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + rw_unlock(&LOCK_grant); close_thread_tables(thd); if (result) @@ -5454,6 +5498,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) rebuild_check_host(); VOID(pthread_mutex_unlock(&acl_cache->lock)); + + if (mysql_bin_log.is_open()) + { + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + rw_unlock(&LOCK_grant); close_thread_tables(thd); if (result) @@ -5523,6 +5574,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) rebuild_check_host(); VOID(pthread_mutex_unlock(&acl_cache->lock)); + + if (mysql_bin_log.is_open()) + { + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + rw_unlock(&LOCK_grant); close_thread_tables(thd); if (result) @@ -5697,6 +5755,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) } VOID(pthread_mutex_unlock(&acl_cache->lock)); + + if (mysql_bin_log.is_open()) + { + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + rw_unlock(&LOCK_grant); close_thread_tables(thd); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 3960236e828..37096fd897e 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -705,6 +705,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, qinfo.db = db; qinfo.db_len = strlen(db); + /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } send_ok(thd, result); @@ -783,6 +784,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) qinfo.db_len = strlen(db); thd->clear_error(); + /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } send_ok(thd, result); @@ -905,6 +907,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) qinfo.db_len = strlen(db); thd->clear_error(); + /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } thd->server_status|= SERVER_STATUS_DB_DROPPED; @@ -931,6 +934,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) tbl_name_len= strlen(tbl->table_name) + 3; if (query_pos + tbl_name_len + 1 >= query_end) { + /* These DDL methods and logging protected with LOCK_mysql_create_db */ write_to_binlog(thd, query, query_pos -1 - query, db, db_len); query_pos= query_data_start; } @@ -943,6 +947,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) if (query_pos != query_data_start) { + /* These DDL methods and logging protected with LOCK_mysql_create_db */ write_to_binlog(thd, query, query_pos -1 - query, db, db_len); } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fc7ed7ff673..a3772e3709a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3237,6 +3237,7 @@ end_with_restore_list: /* ! we write after unlocking the table */ if (!res && !lex->no_write_to_binlog) { + /* Presumably, REPAIR and binlog writing doesn't require synchronization */ if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated @@ -3269,6 +3270,7 @@ end_with_restore_list: /* ! we write after unlocking the table */ if (!res && !lex->no_write_to_binlog) { + /* Presumably, ANALYZE and binlog writing doesn't require synchronization */ if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated @@ -3293,6 +3295,7 @@ end_with_restore_list: /* ! we write after unlocking the table */ if (!res && !lex->no_write_to_binlog) { + /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */ if (mysql_bin_log.is_open()) { thd->clear_error(); // No binlog error generated @@ -3580,6 +3583,7 @@ end_with_restore_list: /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->options|= OPTION_KEEP_LOG; } + /* DDL and binlog write order protected by LOCK_open */ res= mysql_rm_table(thd, first_table, lex->drop_if_exists, lex->drop_temporary); } @@ -3979,13 +3983,9 @@ end_with_restore_list: break; if (end_active_trans(thd)) goto error; + /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list))) - { - if (mysql_bin_log.is_open()) - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); send_ok(thd); - } break; } case SQLCOM_DROP_USER: @@ -3995,15 +3995,9 @@ end_with_restore_list: break; if (end_active_trans(thd)) goto error; + /* Conditionally writes to binlog */ if (!(res= mysql_drop_user(thd, lex->users_list))) - { - if (mysql_bin_log.is_open()) - { - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } send_ok(thd); - } break; } case SQLCOM_RENAME_USER: @@ -4013,15 +4007,9 @@ end_with_restore_list: break; if (end_active_trans(thd)) goto error; + /* Conditionally writes to binlog */ if (!(res= mysql_rename_user(thd, lex->users_list))) - { - if (mysql_bin_log.is_open()) - { - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } send_ok(thd); - } break; } case SQLCOM_REVOKE_ALL: @@ -4029,15 +4017,9 @@ end_with_restore_list: if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) && check_global_access(thd,CREATE_USER_ACL)) break; + /* Conditionally writes to binlog */ if (!(res = mysql_revoke_all(thd, lex->users_list))) - { - if (mysql_bin_log.is_open()) - { - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } send_ok(thd); - } break; } case SQLCOM_REVOKE: @@ -4096,6 +4078,7 @@ end_with_restore_list: check_grant_routine(thd, grants | GRANT_ACL, all_tables, lex->type == TYPE_ENUM_PROCEDURE, 0)) goto error; + /* Conditionally writes to binlog */ res= mysql_routine_grant(thd, all_tables, lex->type == TYPE_ENUM_PROCEDURE, lex->users_list, grants, @@ -4108,16 +4091,11 @@ end_with_restore_list: GRANT_ACL), all_tables, 0, UINT_MAX, 0)) goto error; + /* Conditionally writes to binlog */ res= mysql_table_grant(thd, all_tables, lex->users_list, lex->columns, lex->grant, lex->sql_command == SQLCOM_REVOKE); } - if (!res && mysql_bin_log.is_open()) - { - thd->clear_error(); - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } } else { @@ -4128,16 +4106,11 @@ end_with_restore_list: goto error; } else + /* Conditionally writes to binlog */ res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant, lex->sql_command == SQLCOM_REVOKE); if (!res) { - if (mysql_bin_log.is_open()) - { - thd->clear_error(); - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } if (lex->sql_command == SQLCOM_GRANT) { List_iterator <LEX_USER> str_list(lex->users_list); @@ -4175,6 +4148,7 @@ end_with_restore_list: We WANT to write and we CAN write. ! we write after unlocking the table. */ + /* Presumably, RESET and binlog writing doesn't require synchronization */ if (!lex->no_write_to_binlog && write_to_binlog) { if (mysql_bin_log.is_open()) @@ -4691,20 +4665,16 @@ end_with_restore_list: already puts on CREATE FUNCTION. */ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE) + /* Conditionally writes to binlog */ result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics); else + /* Conditionally writes to binlog */ result= sp_update_function(thd, lex->spname, &lex->sp_chistics); } } switch (result) { case SP_OK: - if (mysql_bin_log.is_open()) - { - thd->clear_error(); - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } send_ok(thd); break; case SP_KEY_NOT_FOUND: @@ -4749,9 +4719,11 @@ end_with_restore_list: } #endif if (lex->sql_command == SQLCOM_DROP_PROCEDURE) - result= sp_drop_procedure(thd, lex->spname); + /* Conditionally writes to binlog */ + result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */ else - result= sp_drop_function(thd, lex->spname); + /* Conditionally writes to binlog */ + result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */ } else { @@ -4764,6 +4736,8 @@ end_with_restore_list: { if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0)) goto error; + + /* Does NOT write to binlog */ if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) { send_ok(thd); @@ -4784,12 +4758,6 @@ end_with_restore_list: switch (result) { case SP_OK: - if (mysql_bin_log.is_open()) - { - thd->clear_error(); - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } send_ok(thd); break; case SP_KEY_NOT_FOUND: @@ -4887,50 +4855,8 @@ end_with_restore_list: { if (end_active_trans(thd)) goto error; - - if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) && - mysql_bin_log.is_open()) - { - String buff; - const LEX_STRING command[3]= - {{ C_STRING_WITH_LEN("CREATE ") }, - { C_STRING_WITH_LEN("ALTER ") }, - { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; - thd->clear_error(); - - buff.append(command[thd->lex->create_view_mode].str, - command[thd->lex->create_view_mode].length); - view_store_options(thd, first_table, &buff); - buff.append(STRING_WITH_LEN("VIEW ")); - /* Test if user supplied a db (ie: we did not use thd->db) */ - if (first_table->db && first_table->db[0] && - (thd->db == NULL || strcmp(first_table->db, thd->db))) - { - append_identifier(thd, &buff, first_table->db, - first_table->db_length); - buff.append('.'); - } - append_identifier(thd, &buff, first_table->table_name, - first_table->table_name_length); - if (lex->view_list.elements) - { - List_iterator_fast<LEX_STRING> names(lex->view_list); - LEX_STRING *name; - int i; - - for (i= 0; name= names++; i++) - { - buff.append(i ? ", " : "("); - append_identifier(thd, &buff, name->str, name->length); - } - buff.append(')'); - } - buff.append(STRING_WITH_LEN(" AS ")); - buff.append(first_table->source.str, first_table->source.length); - - thd->binlog_query(THD::STMT_QUERY_TYPE, - buff.ptr(), buff.length(), FALSE, FALSE); - } + /* Conditionally writes to binlog. */ + res= mysql_create_view(thd, first_table, thd->lex->create_view_mode); break; } case SQLCOM_DROP_VIEW: @@ -4938,13 +4864,8 @@ end_with_restore_list: if (check_table_access(thd, DROP_ACL, all_tables, 0) || end_active_trans(thd)) goto error; - if (!(res= mysql_drop_view(thd, first_table, thd->lex->drop_mode)) && - mysql_bin_log.is_open()) - { - thd->clear_error(); - thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query, thd->query_length, FALSE, FALSE); - } + /* Conditionally writes to binlog. */ + res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); break; } case SQLCOM_CREATE_TRIGGER: @@ -4952,6 +4873,7 @@ end_with_restore_list: if (end_active_trans(thd)) goto error; + /* Conditionally writes to binlog. */ res= mysql_create_or_drop_trigger(thd, all_tables, 1); /* We don't care about trigger body after this point */ @@ -4964,6 +4886,7 @@ end_with_restore_list: if (end_active_trans(thd)) goto error; + /* Conditionally writes to binlog. */ res= mysql_create_or_drop_trigger(thd, all_tables, 0); break; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 63a129918d0..fa33cafdab1 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2287,6 +2287,14 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length) #endif if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); + + /* + If the free_list is not empty, we'll wrongly free some externally + allocated items when cleaning up after validation of the prepared + statement. + */ + DBUG_ASSERT(thd->free_list == NULL); + error= stmt->execute(&expanded_query, test(flags & (ulong) CURSOR_TYPE_READ_ONLY)); if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -2349,6 +2357,13 @@ void mysql_sql_stmt_execute(THD *thd) DBUG_PRINT("info",("stmt: %p", stmt)); + /* + If the free_list is not empty, we'll wrongly free some externally + allocated items when cleaning up after validation of the prepared + statement. + */ + DBUG_ASSERT(thd->free_list == NULL); + if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params, &expanded_query)) goto set_params_data_err; @@ -2827,12 +2842,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) external changes when cleaning up after validation. */ DBUG_ASSERT(thd->change_list.is_empty()); - /* - If the free_list is not empty, we'll wrongly free some externally - allocated items when cleaning up after validation of the prepared - statement. + + /* + The only case where we should have items in the thd->free_list is + after stmt->set_params_from_vars(), which may in some cases create + Item_null objects. */ - DBUG_ASSERT(thd->free_list == NULL); if (error == 0) error= check_prepared_statement(this, name.str != 0); @@ -2930,7 +2945,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) allocated items when cleaning up after execution of this statement. */ DBUG_ASSERT(thd->change_list.is_empty()); - DBUG_ASSERT(thd->free_list == NULL); + + /* + The only case where we should have items in the thd->free_list is + after stmt->set_params_from_vars(), which may in some cases create + Item_null objects. + */ + thd->set_n_backup_statement(this, &stmt_backup); if (expanded_query->length() && alloc_query(thd, (char*) expanded_query->ptr(), diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7796bc35a79..1b91c269e9f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5232,6 +5232,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) + /* Conditionally writes to binlog. */ DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, alter_info->tablespace_op)); if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) @@ -5341,10 +5342,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, !table->s->tmp_table) // no need to touch frm { error=0; + VOID(pthread_mutex_lock(&LOCK_open)); if (new_name != table_name || new_db != db) { thd->proc_info="rename"; - VOID(pthread_mutex_lock(&LOCK_open)); /* Then do a 'simple' rename of the table */ error=0; if (!access(new_name_buff,F_OK)) @@ -5367,7 +5368,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error= -1; } } - VOID(pthread_mutex_unlock(&LOCK_open)); } if (!error) @@ -5376,16 +5376,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, case LEAVE_AS_IS: break; case ENABLE: - VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - VOID(pthread_mutex_unlock(&LOCK_open)); error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: - VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - VOID(pthread_mutex_unlock(&LOCK_open)); error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; @@ -5410,6 +5406,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, table->file->print_error(error, MYF(0)); error= -1; } + VOID(pthread_mutex_unlock(&LOCK_open)); table_list->table=0; // For query cache query_cache_invalidate3(thd, table_list, 0); DBUG_RETURN(error); @@ -6410,7 +6407,7 @@ end_temporary: thd->some_tables_deleted=0; DBUG_RETURN(FALSE); - err1: +err1: if (new_table) { /* close_temporary_table() frees the new_table pointer. */ @@ -6419,7 +6416,7 @@ end_temporary: else VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); - err: +err: DBUG_RETURN(TRUE); } /* mysql_alter_table */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index acb7d5b61df..61d2992ed1b 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -276,8 +276,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) table->triggers->drop_trigger(thd, tables, &stmt_query)); end: - VOID(pthread_mutex_unlock(&LOCK_open)); - start_waiting_global_read_lock(thd); if (!result) { @@ -286,13 +284,16 @@ end: thd->clear_error(); /* Such a statement can always go directly to binlog, no trans cache. */ - Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0, - FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + stmt_query.ptr(), stmt_query.length(), FALSE, FALSE); } + } + + VOID(pthread_mutex_unlock(&LOCK_open)); + start_waiting_global_read_lock(thd); + if (!result) send_ok(thd); - } DBUG_RETURN(result); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 7f6d935ff5e..79ecf12cf27 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -212,6 +212,7 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) SYNOPSIS mysql_create_view() thd - thread handler + views - views to create mode - VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE RETURN VALUE @@ -219,7 +220,7 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) TRUE Error */ -bool mysql_create_view(THD *thd, +bool mysql_create_view(THD *thd, TABLE_LIST *views, enum_view_create_mode mode) { LEX *lex= thd->lex; @@ -548,6 +549,49 @@ bool mysql_create_view(THD *thd, } VOID(pthread_mutex_lock(&LOCK_open)); res= mysql_register_view(thd, view, mode); + + if (mysql_bin_log.is_open()) + { + String buff; + const LEX_STRING command[3]= + {{ C_STRING_WITH_LEN("CREATE ") }, + { C_STRING_WITH_LEN("ALTER ") }, + { C_STRING_WITH_LEN("CREATE OR REPLACE ") }}; + + buff.append(command[thd->lex->create_view_mode].str, + command[thd->lex->create_view_mode].length); + view_store_options(thd, views, &buff); + buff.append(STRING_WITH_LEN("VIEW ")); + /* Test if user supplied a db (ie: we did not use thd->db) */ + if (views->db && views->db[0] && + (thd->db == NULL || strcmp(views->db, thd->db))) + { + append_identifier(thd, &buff, views->db, + views->db_length); + buff.append('.'); + } + append_identifier(thd, &buff, views->table_name, + views->table_name_length); + if (lex->view_list.elements) + { + List_iterator_fast<LEX_STRING> names(lex->view_list); + LEX_STRING *name; + int i; + + for (i= 0; name= names++; i++) + { + buff.append(i ? ", " : "("); + append_identifier(thd, &buff, name->str, name->length); + } + buff.append(')'); + } + buff.append(STRING_WITH_LEN(" AS ")); + buff.append(views->source.str, views->source.length); + + thd->binlog_query(THD::STMT_QUERY_TYPE, + buff.ptr(), buff.length(), FALSE, FALSE); + } + VOID(pthread_mutex_unlock(&LOCK_open)); if (view->revision != 1) query_cache_invalidate3(thd, view, 0); @@ -1318,13 +1362,13 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) enum legacy_db_type not_used; DBUG_ENTER("mysql_drop_view"); + VOID(pthread_mutex_lock(&LOCK_open)); for (view= views; view; view= view->next_local) { TABLE_SHARE *share; frm_type_enum type= FRMTYPE_ERROR; build_table_filename(path, sizeof(path), view->db, view->table_name, reg_ext, 0); - VOID(pthread_mutex_lock(&LOCK_open)); if (access(path, F_OK) || FRMTYPE_VIEW != (type= mysql_frm_type(thd, path, ¬_used))) @@ -1336,7 +1380,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), name); - VOID(pthread_mutex_unlock(&LOCK_open)); continue; } if (type == FRMTYPE_TABLE) @@ -1353,7 +1396,6 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) non_existant_views.append(','); non_existant_views.append(String(view->table_name,system_charset_info)); } - VOID(pthread_mutex_unlock(&LOCK_open)); continue; } if (my_delete(path, MYF(MY_WME))) @@ -1374,8 +1416,16 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) } query_cache_invalidate3(thd, view, 0); sp_cache_invalidate(); - VOID(pthread_mutex_unlock(&LOCK_open)); } + + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); + } + + VOID(pthread_mutex_unlock(&LOCK_open)); if (error) { DBUG_RETURN(TRUE); diff --git a/sql/sql_view.h b/sql/sql_view.h index 7e54d57cfdf..fc480167216 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -16,7 +16,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -bool mysql_create_view(THD *thd, +bool mysql_create_view(THD *thd, TABLE_LIST *view, enum_view_create_mode mode); bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, diff --git a/sql/time.cc b/sql/time.cc index 0461f7723c6..25a1995dd01 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -25,14 +25,25 @@ #ifndef TESTTIME +/* + Name description of interval names used in statements. + + 'interval_type_to_name' is ordered and sorted on interval size and + interval complexity. + Order of elements in 'interval_type_to_name' should correspond to + the order of elements in 'interval_type' enum + + See also interval_type, interval_names +*/ + LEX_STRING interval_type_to_name[INTERVAL_LAST] = { { C_STRING_WITH_LEN("YEAR")}, { C_STRING_WITH_LEN("QUARTER")}, { C_STRING_WITH_LEN("MONTH")}, + { C_STRING_WITH_LEN("WEEK")}, { C_STRING_WITH_LEN("DAY")}, { C_STRING_WITH_LEN("HOUR")}, { C_STRING_WITH_LEN("MINUTE")}, - { C_STRING_WITH_LEN("WEEK")}, { C_STRING_WITH_LEN("SECOND")}, { C_STRING_WITH_LEN("MICROSECOND")}, { C_STRING_WITH_LEN("YEAR_MONTH")}, @@ -278,9 +289,9 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, my_bool *in_dst_time_gap) bool str_to_time_with_warn(const char *str, uint length, TIME *l_time) { - int was_cut; - bool ret_val= str_to_time(str, length, l_time, &was_cut); - if (was_cut) + int warning; + bool ret_val= str_to_time(str, length, l_time, &warning); + if (ret_val || warning) make_truncated_value_warning(current_thd, str, length, MYSQL_TIMESTAMP_TIME, NullS); return ret_val; diff --git a/storage/myisam/sort.c b/storage/myisam/sort.c index 099c3173396..9d7eda9f5ba 100644 --- a/storage/myisam/sort.c +++ b/storage/myisam/sort.c @@ -324,7 +324,7 @@ pthread_handler_t thr_find_all_keys(void *arg) if (info->sort_info->got_error) goto err; - if (info->keyinfo->flag && HA_VAR_LENGTH_KEY) + if (info->keyinfo->flag & HA_VAR_LENGTH_KEY) { info->write_keys=write_keys_varlen; info->read_to_buffer=read_to_buffer_varlen; @@ -517,7 +517,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) { if (got_error) continue; - if (sinfo->keyinfo->flag && HA_VAR_LENGTH_KEY) + if (sinfo->keyinfo->flag & HA_VAR_LENGTH_KEY) { sinfo->write_keys=write_keys_varlen; sinfo->read_to_buffer=read_to_buffer_varlen; |