Below is the list of changes that have just been committed into a local
5.1 repository of msvensson. When msvensson does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2006-07-30 19:16:51+02:00, msvensson@shellback.(none) +4 -0
Add new commands to mysqltest - to make it easier to write portable test scripts
client/Makefile.am@stripped, 2006-07-30 19:16:19+02:00, msvensson@shellback.(none) +2 -1
Link mysqltest with mysys library
client/mysqltest.c@stripped, 2006-07-30 19:16:20+02:00, msvensson@shellback.(none) +412 -55
Add new commands to mysqltest:
- remove_file
- copy_file
- file_exists
- write_file
- perl
mysql-test/r/mysqltest.result@stripped, 2006-07-30 19:16:20+02:00, msvensson@shellback.(none) +11 -0
Update result file
mysql-test/t/mysqltest.test@stripped, 2006-07-30 19:16:47+02:00, msvensson@shellback.(none) +75 -0
Add tests for new commands
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: msvensson
# Host: shellback.(none)
# Root: /home/msvensson/mysql/my51-mysqltest-new-commands
--- 1.73/client/Makefile.am 2006-07-30 19:17:02 +02:00
+++ 1.74/client/Makefile.am 2006-07-30 19:17:02 +02:00
@@ -46,7 +46,8 @@
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 \
--- 1.40/mysql-test/r/mysqltest.result 2006-07-30 19:17:02 +02:00
+++ 1.41/mysql-test/r/mysqltest.result 2006-07-30 19:17:02 +02:00
@@ -467,3 +467,14 @@
1 1
1 4
drop table t1;
+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
--- 1.51/mysql-test/t/mysqltest.test 2006-07-30 19:17:02 +02:00
+++ 1.52/mysql-test/t/mysqltest.test 2006-07-30 19:17:02 +02:00
@@ -1159,3 +1159,78 @@
--replace_regex /A/C/ /B/D/i /3/2/ /2/1/
select * from t1;
drop table t1;
+
+# ----------------------------------------------------------------------------
+# 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
+
+# ----------------------------------------------------------------------------
+# 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;
+print "hello\n";
+EOF
+
+perl;
+ # Print "hello"
+ print "hello\n";
+EOF
--- 1.220/client/mysqltest.c 2006-07-30 19:17:02 +02:00
+++ 1.221/client/mysqltest.c 2006-07-30 19:17:02 +02:00
@@ -24,7 +24,7 @@
* Jani
**/
-#define MTEST_VERSION "2.6"
+#define MTEST_VERSION "2.7"
#include <my_global.h>
#include <mysql_embed.h>
@@ -333,7 +333,8 @@
Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
Q_IF,
Q_DISABLE_PARSING, Q_ENABLE_PARSING,
-Q_REPLACE_REGEX,
+Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST,
+Q_WRITE_FILE, Q_COPY_FILE, Q_PERL,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
@@ -423,6 +424,11 @@
"disable_parsing",
"enable_parsing",
"replace_regex",
+ "remove_file",
+ "file_exists",
+ "write_file",
+ "copy_file",
+ "perl",
0
};
@@ -468,7 +474,7 @@
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);
+ const char* query_end, my_bool pass_through_escape_chars);
static void str_to_file(const char *fname, char *str, int size);
#ifdef __WIN__
@@ -501,8 +507,8 @@
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)
+static 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;
@@ -510,7 +516,7 @@
VAR* v;
DBUG_ENTER("do_eval");
- for (p= query; (c = *p); ++p)
+ for (p= query; (c = *p) && p < query_end; ++p)
{
switch(c) {
case '$':
@@ -533,9 +539,9 @@
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 $ */
+ /* Set escaped only if next char is \, " or $ */
escaped = 1;
if (pass_through_escape_chars)
@@ -556,6 +562,108 @@
}
+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 string argument */
+ const char *description; /* Description of the argument */
+};
+
+static void check_command_args(struct st_query *command, const char *arguments,
+ const struct command_arg *args, int num_args)
+{
+ 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 surrounded by spaces */
+ case ARG_STRING:
+ start= ptr;
+ /* Find end of arg */
+ while (*ptr && !my_isspace(charset_info, *ptr))
+ ptr++;
+ init_dynamic_string(arg->ds, 0, 256, 256);
+ do_eval(arg->ds, start, ptr, FALSE);
+ command->last_argument= (char*)ptr;
+ if (*ptr)
+ ptr++;
+ 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;
+ 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;
+}
+
+
+static void handle_command_error(struct st_query *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", command->first_word_len, command->query);
+ for (i= 0; i < command->expected_errors; i++)
+ {
+ DBUG_PRINT("info", ("expected error: %d",
+ command->expected_errno[i].code.errnum));
+ if ((command->expected_errno[i].type == ERR_ERRNO) &&
+ (command->expected_errno[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_errno[0].type == ERR_ERRNO &&
+ command->expected_errno[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_errno[0].code.errnum);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
static void close_cons()
{
DBUG_ENTER("close_cons");
@@ -743,7 +851,7 @@
init_dynamic_string(&res_ds, "", stat_info.st_size+256, 256);
if (eval_result)
{
- do_eval(&res_ds, tmp, FALSE);
+ 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)
@@ -1168,7 +1276,7 @@
init_dynamic_string(&ds_cmd, 0, query->query_len+256, 256);
/* Eval the command, thus replacing all environment variables */
- do_eval(&ds_cmd, cmd, TRUE);
+ do_eval(&ds_cmd, cmd, query->end, TRUE);
cmd= ds_cmd.str;
DBUG_PRINT("info", ("Executing '%s' as '%s'",
@@ -1484,7 +1592,7 @@
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));
@@ -1506,6 +1614,291 @@
/*
+ SYNOPSIS
+ do_remove_file
+ command called command
+
+ DESCRIPTION
+ remove_file <file_name>
+ Remove the file <file_name>
+*/
+
+static void do_remove_file(struct st_query *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
+*/
+
+static void do_copy_file(struct st_query *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
+*/
+
+static void do_file_exist(struct st_query *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 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.
+*/
+
+static int my_getc(FILE *file)
+{
+ if (line_buffer_pos == line_buffer)
+ return fgetc(file);
+ return *--line_buffer_pos;
+}
+
+
+static void my_ungetc(int c)
+{
+ *line_buffer_pos++= (char) c;
+}
+
+
+static my_bool match_delimiter(int c, const char* delim, uint length)
+{
+ uint i;
+ char tmp[MAX_DELIMITER];
+
+ if (c != *delim)
+ return 0;
+
+ for (i= 1; i < length &&
+ (c= my_getc(cur_file->file)) == *(delim + i);
+ i++)
+ tmp[i]= c;
+
+ if (i == length)
+ return 1; /* Found delimiter */
+
+ /* didn't find delimiter, push back things that we read */
+ my_ungetc(c);
+ while (i > 1)
+ my_ungetc(tmp[--i]);
+ return 0;
+}
+
+
+static void read_until_EOF(DYNAMIC_STRING* ds)
+{
+ int c;
+ DBUG_ENTER("read_until_EOF");
+
+ /* Read from file until delimiter EOF is found */
+ while (1)
+ {
+ c= my_getc(cur_file->file);
+
+ if (feof(cur_file->file))
+ die("End of file encountered before 'EOF' delimiter was found");
+
+ if (match_delimiter(c, "EOF", 3))
+ {
+ DBUG_PRINT("exit", ("Found EOF"));
+ 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>;
+ <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 EOF to "file_name"
+
+ NOTE! Overwrites existing file
+
+*/
+
+static void do_write_file(struct st_query *command)
+{
+ DYNAMIC_STRING ds_content;
+ DYNAMIC_STRING ds_filename;
+ const struct command_arg write_file_args[] = {
+ "filename", ARG_STRING, TRUE, &ds_filename, "File to write to",
+ };
+ DBUG_ENTER("do_write_file");
+
+ check_command_args(command,
+ command->first_argument,
+ write_file_args,
+ sizeof(write_file_args)/sizeof(struct command_arg));
+
+ init_dynamic_string(&ds_content, "", 1024, 1024);
+ read_until_EOF(&ds_content);
+ 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);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ SYNOPSIS
+ do_perl
+ command command handle
+
+ DESCRIPTION
+ perl;
+ <perlscript line 1>
+ <...>
+ <perlscript line n>
+ EOF
+
+ Execute everything after "perl" until EOF as perl.
+ Useful for doing more advanced things
+ but still being able to execute it on all platforms.
+
+ The function sets delimiter to EOF and remembers that this
+ is a perl command by setting "perl mode". The following lines
+ will then be parsed as any normal query, but when searching
+ for command in get_query_type, this function will be called
+ again since "perl mode" is on and the perl script can be
+ executed.
+*/
+
+static void do_perl(struct st_query *command)
+{
+ int error;
+ char buf[FN_REFLEN];
+ FILE *res_file;
+ DYNAMIC_STRING ds_script;
+ DBUG_ENTER("do_perl");
+
+ init_dynamic_string(&ds_script, "", 1024, 1024);
+ read_until_EOF(&ds_script);
+
+ 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);
+ 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 \
@@ -1534,7 +1927,7 @@
DYNAMIC_STRING ds_echo;
init_dynamic_string(&ds_echo, "", command->query_len, 256);
- do_eval(&ds_echo, command->first_argument, FALSE);
+ 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);
@@ -2900,50 +3293,9 @@
}
-/*
- Read characters from line buffer or file. This is needed to allow
- my_ungetc() to buffer MAX_DELIMITER 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;
-}
-
-
my_bool end_of_query(int c)
{
- uint i;
- char tmp[MAX_DELIMITER];
-
- if (c != *delimiter)
- return 0;
-
- for (i= 1; i < delimiter_length &&
- (c= my_getc(cur_file->file)) == *(delimiter + i);
- i++)
- tmp[i]= c;
-
- if (i == delimiter_length)
- return 1; /* Found delimiter */
-
- /* didn't find delimiter, push back things that we read */
- my_ungetc(c);
- while (i > 1)
- my_ungetc(tmp[--i]);
- return 0;
+ return match_delimiter(c, delimiter, delimiter_length);
}
@@ -4786,7 +5138,7 @@
if (command->type == Q_EVAL)
{
init_dynamic_string(&eval_query, "", command->query_len+256, 1024);
- do_eval(&eval_query, command->query, FALSE);
+ do_eval(&eval_query, command->query, command->end, FALSE);
query = eval_query.str;
query_len = eval_query.length;
}
@@ -5390,6 +5742,11 @@
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_REMOVE_FILE: do_remove_file(q); break;
+ case Q_FILE_EXIST: do_file_exist(q); break;
+ case Q_WRITE_FILE: do_write_file(q); break;
+ case Q_COPY_FILE: do_copy_file(q); break;
+ case Q_PERL: do_perl(q); break;
case Q_DELIMITER:
do_delimiter(q);
break;
| Thread |
|---|
| • bk commit into 5.1 tree (msvensson:1.2255) | msvensson | 31 Jul |