List:Internals« Previous MessageNext Message »
From:msvensson Date:July 15 2005 5:51pm
Subject:bk commit into 4.1 tree (msvensson:1.2327) BUG#11316
View as plain text  
Below is the list of changes that have just been committed into a local
4.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
  1.2327 05/07/15 17:51:43 msvensson@neptunus.(none) +17 -0
  BUG#11316 mysqltest, problems when assigning value with '#' to $variable
   - Fixed problem, only detect comment if the # is on start of line AND starting line of
the current command.
   - Wrote tests for most of the mysqltest commands, added stricter checking of correct
syntax.

  mysql-test/include/mysqltest_while.inc
    1.1 05/07/15 17:51:38 msvensson@neptunus.(none) +137 -0
    New file to test too many while levels

  mysql-test/t/rpl_until.test
    1.15 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Missing delimiter

  mysql-test/t/rpl_rotate_logs.test
    1.51 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Correct wrong syntax
    Superfluos ;

  mysql-test/t/rpl_insert_id.test
    1.9 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Missing ;

  mysql-test/t/rpl_flush_log_loop.test
    1.8 05/07/15 17:51:38 msvensson@neptunus.(none) +2 -2
    Fix after detecting wrong syntax, missing ;
    Discussed with lars.

  mysql-test/t/rpl_drop_temp.test
    1.2 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Correct wrong syntax
    Superfluos ;

  mysql-test/t/rpl_deadlock.test
    1.3 05/07/15 17:51:38 msvensson@neptunus.(none) +3 -3
    Correct wrong syntax
    Superfluos ;

  mysql-test/t/rpl_change_master.test
    1.7 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Correct wrong syntax
    Superfluos ;

  mysql-test/t/ndb_autodiscover2.test
    1.7 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Correct wrong syntax
    Superfluos ;

  mysql-test/t/mysqltest.test
    1.4 05/07/15 17:51:38 msvensson@neptunus.(none) +384 -2
    Add several new tests  for mysqltest.
    Foxus on detecting wrong syntax in test files.
    Use exec with expected error to execute test scripts that will kill mysqltest
    Change some negative test that were previously commented out to use the above method.

  mysql-test/t/innodb-lock.test
    1.7 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Correct wrong syntax
    Superfluos ;

  mysql-test/t/innodb-deadlock.test
    1.7 05/07/15 17:51:38 msvensson@neptunus.(none) +3 -3
    Correct wrong syntax
    Superfluos ;

  mysql-test/r/rpl_flush_log_loop.result
    1.16 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -1
    Updated test result.
    Approved by lars

  mysql-test/r/mysqltest.result
    1.4 05/07/15 17:51:38 msvensson@neptunus.(none) +121 -0
    Updated test results

  mysql-test/mysql-test-run.sh
    1.255 05/07/15 17:51:38 msvensson@neptunus.(none) +1 -0
    export MYSQL_TEST environment variable, used from msyqltest.test

  mysql-test/mysql-test-run.pl
    1.33 05/07/15 17:51:38 msvensson@neptunus.(none) +5 -0
    export MYSQL_TEST environment variable, used from msyqltest.test

  mysql-test/include/mysqltest_while.inc
    1.0 05/07/15 17:51:38 msvensson@neptunus.(none) +0 -0
    BitKeeper file
/home/msvensson/mysql/bug11316/my41-bug11316/mysql-test/include/mysqltest_while.inc

  client/mysqltest.c
    1.170 05/07/15 17:51:37 msvensson@neptunus.(none) +460 -125
    Updated mysql test to do stricter checking of syntax. For example when the number 
    of arguments to a command is known, everything else is "junk" => die. 
    Better checking of argument types.
    Added better debug printouts.
    Added improved printouts when wrong syntax is detected.
    Fix two bugs where mysqltest could not detect end of comamnd properly, as described in
bug#11316
    Fix segfault when performing too many source commands.
    Fix segfault when doing too many while loop levels.
    Add printout of line number in die
    Remove lineno and \n in all strings passed to die function.
    Decrese BLOCK_STACK_DEPTH from 32 to 16, does any test use more than 1 level?

# 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:	neptunus.(none)
# Root:	/home/msvensson/mysql/bug11316/my41-bug11316

--- 1.254/mysql-test/mysql-test-run.sh	2005-06-21 14:24:12 +02:00
+++ 1.255/mysql-test/mysql-test-run.sh	2005-07-15 17:51:38 +02:00
@@ -714,6 +714,7 @@
 fi
 MYSQL_TEST_BIN=$MYSQL_TEST
 MYSQL_TEST="$MYSQL_TEST $MYSQL_TEST_ARGS"
+export MYSQL_TEST
 GDB_CLIENT_INIT=$MYSQL_TMP_DIR/gdbinit.client
 GDB_MASTER_INIT=$MYSQL_TMP_DIR/gdbinit.master
 GDB_SLAVE_INIT=$MYSQL_TMP_DIR/gdbinit.slave

--- 1.14/mysql-test/t/rpl_until.test	2004-12-03 11:22:07 +01:00
+++ 1.15/mysql-test/t/rpl_until.test	2005-07-15 17:51:38 +02:00
@@ -60,7 +60,7 @@
 # this should stop immideately
 start slave until master_log_file='master-bin.000001', master_log_pos=561;
 # 2 is not enough when running with valgrind
-real_sleep 4
+--real_sleep 4
 # here the sql slave thread should be stopped
 --replace_result $MASTER_MYPORT MASTER_MYPORT bin.000005 bin.000004 bin.000006 bin.000004
bin.000007 bin.000004
 --replace_column 1 # 9 # 23 # 33 #

--- 1.6/mysql-test/t/rpl_change_master.test	2004-03-20 11:29:41 +01:00
+++ 1.7/mysql-test/t/rpl_change_master.test	2005-07-15 17:51:38 +02:00
@@ -8,7 +8,7 @@
 insert into t1 values(2);
 save_master_pos;
 connection slave;
---real_sleep 3; # can't sync_with_master as we should be blocked
+--real_sleep 3 # can't sync_with_master as we should be blocked
 stop slave;
 select * from t1;
 --replace_result $MASTER_MYPORT MASTER_MYPORT

--- 1.2/mysql-test/t/rpl_deadlock.test	2005-03-23 19:19:08 +01:00
+++ 1.3/mysql-test/t/rpl_deadlock.test	2005-07-15 17:51:38 +02:00
@@ -58,7 +58,7 @@
 enable_query_log;
 select * from t1 for update;
 start slave;
---sleep 3; # hope that slave is blocked now
+--sleep 3 # hope that slave is blocked now
 insert into t2 values(22); # provoke deadlock, slave should be victim
 commit;
 sync_with_master;
@@ -76,7 +76,7 @@
 begin;
 select * from t2 for update; # hold lock
 start slave;
---sleep 10; # slave should have blocked, and be retrying
+--sleep 10 # slave should have blocked, and be retrying
 commit;
 sync_with_master;
 select * from t1; # check that slave succeeded finally
@@ -97,7 +97,7 @@
 begin;
 select * from t2 for update;
 start slave;
---sleep 10;
+--sleep 10
 commit;
 sync_with_master;
 select * from t1;

--- 1.1/mysql-test/t/rpl_drop_temp.test	2005-02-14 23:46:49 +01:00
+++ 1.2/mysql-test/t/rpl_drop_temp.test	2005-07-15 17:51:38 +02:00
@@ -9,5 +9,5 @@
 connection master;
 disconnect master;
 connection slave;
---real_sleep 3; # time for DROP to be written
+--real_sleep 3 # time for DROP to be written
 show status like 'Slave_open_temp_tables';

--- 1.32/mysql-test/mysql-test-run.pl	2005-06-23 17:35:07 +02:00
+++ 1.33/mysql-test/mysql-test-run.pl	2005-07-15 17:51:38 +02:00
@@ -2129,6 +2129,11 @@
     mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[]);
   }
 
+  # ----------------------------------------------------------------------
+  # export MYSQL_TEST variable containing <path>/mysqltest <args>
+  # ----------------------------------------------------------------------
+  $ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args);
+
   return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,"");
 }
 

--- 1.3/mysql-test/r/mysqltest.result	2004-11-02 19:13:23 +01:00
+++ 1.4/mysql-test/r/mysqltest.result	2005-07-15 17:51:38 +02:00
@@ -7,6 +7,7 @@
 select otto from (select 1 as otto) as t1;
 otto
 1
+mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed:
1054: Unknown column 'friedrich' in 'field list'
 select friedrich from (select 1 as otto) as t1;
 ERROR 42S22: Unknown column 'friedrich' in 'field list'
 select otto from (select 1 as otto) as t1;
@@ -15,10 +16,12 @@
 select otto from (select 1 as otto) as t1;
 otto
 1
+mysqltest: At line 1: query 'select otto from (select 1 as otto) as t1' succeeded -
should have failed with sqlstate 42S22...
 select friedrich from (select 1 as otto) as t1;
 ERROR 42S22: Unknown column 'friedrich' in 'field list'
 select friedrich from (select 1 as otto) as t1;
 ERROR 42S22: Unknown column 'friedrich' in 'field list'
+mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with
wrong sqlstate 42S22 instead of 00000...
 select otto from (select 1 as otto) as t1;
 otto
 1
@@ -135,6 +138,8 @@
 select 1146 as "after_!errno_masked_error" ;
 after_!errno_masked_error
 1146
+mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of
1000...
+mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of
1000...
 garbage ;
 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 'garbage' at line 1
 select 1064 as "after_--enable_abort_on_error" ;
@@ -142,3 +147,119 @@
 1064
 select 3 from t1 ;
 ERROR 42S02: Table 'test.t1' doesn't exist
+mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of
1064...
+mysqltest: At line 1: query 'select 3 from t1' failed: 1146: Table 'test.t1' doesn't
exist
+hello
+hello
+;;;;;;;;
+# MySQL: -- The
+mysqltest: At line 1: End of line junk detected: "6"
+mysqltest: At line 1: End of line junk detected: "6"
+mysqltest: At line 1: Missing delimiter
+mysqltest: At line 1: Extra delimiter ";" found
+MySQL
+"MySQL"
+MySQL: The world''s most popular open source database
+"MySQL: The world's most popular open source database"
+MySQL: The world''s
+most popular open
+source database
+# MySQL: The world''s
+# most popular open
+# source database
+- MySQL: The world''s
+- most popular open
+- source database
+- MySQL: The world''s
+-- most popular open
+-- source database
+# MySQL: The
+--world''s
+# most popular
+-- open
+- source database
+"MySQL: The world's most popular; open source database"
+"MySQL: The world's most popular ; open source database"
+"MySQL: The world's most popular ;open source database"
+echo message echo message
+
+mysqltest: At line 1: Empty variable
+sh: -c: line 0: syntax error near unexpected token `;'
+sh: -c: line 0: `;'
+mysqltest: At line 1: command ";" failed
+mysqltest: At line 1: Missing argument in exec
+MySQL
+"MySQL"
+MySQL: The
+world''s most
+popular open
+source database
+# MySQL: The
+# world''s most
+# popular open
+# source database
+-- MySQL: The
+-- world''s most
+-- popular open
+-- source database
+# MySQL: The
+- world''s most
+-- popular open
+# source database
+'$message'
+"$message"
+hej
+hej 
+hej
+mysqltest: At line 1: Missing arguments to let
+mysqltest: At line 1: Missing variable name in let
+mysqltest: At line 1: Variable name in hi=hi does not start with '$'
+mysqltest: At line 1: Missing assignment operator in let
+mysqltest: At line 1: Missing assignment operator in let
+mysqltest: At line 1: Missing arguments to let
+mysqltest: At line 1: Missing variable name in let
+mysqltest: At line 1: Variable name in =hi does not start with '$'
+mysqltest: At line 1: Missing assignment operator in let
+mysqltest: At line 1: Missing file name in source
+mysqltest: At line 1: Could not open file ./non_existingFile
+mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are
nesting too deep
+mysqltest: In included file "./var/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
+mysqltest: At line 1: Missing argument to sleep
+mysqltest: At line 1: Invalid argument to sleep "abc"
+1
+2
+101
+hej
+1
+mysqltest: At line 1: Missing arguments to inc
+mysqltest: At line 1: First argument to inc must be a variable (start with $)
+mysqltest: At line 1: End of line junk detected: "1000"
+4
+4
+-1
+-2
+99
+hej
+-1
+mysqltest: At line 1: Missing arguments to dec
+mysqltest: At line 1: First argument to dec must be a variable (start with $)
+mysqltest: At line 1: End of line junk detected: "1000"
+mysqltest: At line 1: Missing arguments to system, nothing to do!
+mysqltest: At line 1: Missing arguments to system, nothing to do!
+sh: NonExistsinfComamdn: command not found
+mysqltest: At line 1: system command 'NonExistsinfComamdn' failed
+test
+test2
+test3
+test4
+1
+mysqltest: In included file "./include/mysqltest_while.inc": At line 32: 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 of block before beginning
+mysqltest: At line 1: query '' failed: 1065: Query was empty
+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 '{'

--- 1.3/mysql-test/t/mysqltest.test	2004-11-02 19:13:23 +01:00
+++ 1.4/mysql-test/t/mysqltest.test	2005-07-15 17:51:38 +02:00
@@ -3,6 +3,24 @@
 #
 # Test of mysqltest itself
 #
+# There are three rules that determines what belong to each command
+# 1. A normal command is delimited by the <delimiter> which by default is
+#    set to ';'
+#
+#   ex: | select *
+#       |   from t1;
+#       |
+#   Command: "select * from t1"
+#
+# 2. Special case is a line that starts with "--", this is a comment
+#    ended when the new line character is reached. But the first word
+#    in the comment may contain a valid command, which then will be
+#    executed. This can be useful when sending commands that
+#    contains <delimiter>
+#
+# 3. Special case is also a line that starts with '#' which is treated
+#     as a comment and will be ended by new line character
+#
 # ============================================================================
 
 # ----------------------------------------------------------------------------
@@ -37,7 +55,9 @@
 
 # expectation <> response
 #--error 0
-#select friedrich from (select 1 as otto) as t1;
+#select friedrich from (select 1 as otto) as t1
+--error 1
+--exec echo "select friedrich from (select 1 as otto) as t1;" | $MYSQL_TEST  2>&1
 
 # expectation = response
 --error 1054
@@ -65,6 +85,9 @@
 #!S42S22 select otto from (select 1 as otto) as t1;
 #--error S42S22
 #select otto from (select 1 as otto) as t1;
+--error 1
+--exec echo "error S42S22; select otto from (select 1 as otto) as t1;" | $MYSQL_TEST 
2>&1
+
 
 
 # ----------------------------------------------------------------------------
@@ -80,7 +103,8 @@
 #!S00000 select friedrich from (select 1 as otto) as t1;
 #--error S00000
 #select friedrich from (select 1 as otto) as t1;
-
+--error 1
+--exec echo "error S00000; select friedrich from (select 1 as otto) as t1;" | $MYSQL_TEST
 2>&1
 
 # ----------------------------------------------------------------------------
 # test cases for $mysql_errno
@@ -262,6 +286,8 @@
 # select 3 from t1 ;
 # --error 1000
 # select 3 from t1 ;
+--error 1
+--exec echo "disable_abort_on_error; error 1000; select 3 from t1; error 1000; select 3
from t1;" | $MYSQL_TEST  2>&1
 
 # ----------------------------------------------------------------------------
 # Switch the abort on error on and check the effect on $mysql_errno
@@ -286,3 +312,359 @@
 #select 3 from t1 ;
 #
 #select 3 from t1 ;
+--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
+
+
+# ----------------------------------------------------------------------------
+# Test comments
+# ----------------------------------------------------------------------------
+
+# This is a comment
+# This is a ;  comment
+# This is a -- comment
+-- This is also a comment
+-- # This is also a comment
+-- This is also a ; comment
+
+# ----------------------------------------------------------------------------
+# Test comments with embedded command
+# ----------------------------------------------------------------------------
+
+--echo hello
+--     echo hello
+--    echo ;;;;;;;;
+
+--echo # MySQL: -- The
+
+# ----------------------------------------------------------------------------
+# Test detect end of line "junk"
+# Most likely causes by a missing delimiter
+# ----------------------------------------------------------------------------
+
+# Too many parameters to function
+--error 1
+--exec echo "sleep 5 6;" | $MYSQL_TEST 2>&1
+
+# Too many parameters to function
+--error 1
+--exec echo "--sleep 5 6" | $MYSQL_TEST 2>&1
+
+#
+# Missing delimiter
+# The comment will be "sucked into" the sleep command since
+# delimiter is missing until after "show status"
+--error 1
+--exec echo -e "sleep 4\n # A comment\nshow status;" | $MYSQL_TEST 2>&1
+
+#
+# Extra delimiter
+#
+--error 1
+--exec echo "--sleep 4;" | $MYSQL_TEST 2>&1
+
+
+# Allow trailing # comment
+--sleep 1 # Wait for insert delayed to be executed.
+--sleep 1 	 # Wait for insert delayed to be executed.
+
+
+# ----------------------------------------------------------------------------
+# Test echo command
+# ----------------------------------------------------------------------------
+
+echo MySQL;
+echo "MySQL";
+echo MySQL: The world''s most popular open source database;
+echo "MySQL: The world's most popular open source database";
+
+echo MySQL: The world''s
+     most popular open
+     source database;
+
+echo # MySQL: The world''s
+# most popular open
+# source database;
+
+echo - MySQL: The world''s
+- most popular open
+- source database;
+
+echo - MySQL: The world''s
+-- most popular open
+-- source database;
+
+echo # MySQL: The
+--world''s
+# most popular
+-- open
+- source database;
+
+echo "MySQL: The world's most popular; open source database";
+echo "MySQL: The world's most popular ; open source database";
+echo "MySQL: The world's most popular ;open source database";
+echo echo message echo message;
+
+
+echo ;
+
+# Illegal use of echo
+
+--error 1
+--exec echo "echo $;" | $MYSQL_TEST 2>&1
+
+
+# ----------------------------------------------------------------------------
+# Test exec command
+# ----------------------------------------------------------------------------
+
+# Illegal use of exec
+--error 1
+--exec echo "--exec ;" | $MYSQL_TEST 2>&1
+
+--error 1
+--exec echo "--exec " | $MYSQL_TEST 2>&1
+
+# ----------------------------------------------------------------------------
+# Test let command
+# ----------------------------------------------------------------------------
+
+let $message=MySQL;
+echo $message;
+
+let $message="MySQL";
+echo $message;
+
+let $message= MySQL: The
+ world''s most
+ popular open
+ source database;
+echo $message;
+
+let $message= # MySQL: The
+# world''s most
+# popular open
+# source database;
+echo $message;
+
+let $message=  -- MySQL: The
+-- world''s most
+-- popular open
+-- source database;
+echo $message;
+
+let $message=  # MySQL: The
+- world''s most
+-- popular open
+# source database;
+echo $message;
+
+echo '$message';
+echo "$message";
+
+let $1=hej;
+echo $1;
+
+let   $1   =hej ;
+echo $1;
+
+let $1 = hej;
+echo $1;
+
+
+# Test illegal uses of let
+
+--error 1
+--exec echo "let ;" | $MYSQL_TEST 2>&1
+
+--error 1
+--exec echo "let $=hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let hi=hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let $1 hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let $m hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let $hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let $ hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let =hi;" | $MYSQL_TEST  2>&1
+
+--error 1
+--exec echo "let hi;" | $MYSQL_TEST  2>&1
+
+# ----------------------------------------------------------------------------
+# Test source command
+# ----------------------------------------------------------------------------
+
+# Test illegal uses of source
+
+--error 1
+--exec echo "source ;" | $MYSQL_TEST 2>&1
+
+--error 1
+--exec echo "source non_existingFile;" | $MYSQL_TEST 2>&1
+
+# Too many source
+--exec echo "source var/tmp/recursive.sql;" > var/tmp/recursive.sql
+--error 1
+--exec echo "source var/tmp/recursive.sql;" | $MYSQL_TEST 2>&1
+
+# Source a file with error
+--exec echo "garbage ;" > var/tmp/error.sql
+--error 1
+--exec echo "source var/tmp/error.sql;" | $MYSQL_TEST 2>&1
+
+
+# ----------------------------------------------------------------------------
+# Test sleep command
+# ----------------------------------------------------------------------------
+
+sleep 0.5;
+sleep 1;
+real_sleep 1;
+
+# Missing parameter
+--error 1
+--exec echo "sleep ;" | $MYSQL_TEST 2>&1
+
+# Illegal parameter
+--error 1
+--exec echo "sleep abc;" | $MYSQL_TEST 2>&1
+
+# ----------------------------------------------------------------------------
+# Test inc
+# ----------------------------------------------------------------------------
+inc $i;
+echo $i;
+inc $i;
+echo $i;
+let $i=100;
+inc $i;
+echo $i;
+
+let $i=hej;
+echo $i;
+inc $i;
+echo $i;
+
+--error 1
+--exec echo "inc;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "inc i;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "let \$i=100; inc \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1
+
+inc $i; inc $i; inc $i; --echo $i
+echo $i;
+
+
+# ----------------------------------------------------------------------------
+# Test dec
+# ----------------------------------------------------------------------------
+
+dec $d;
+echo $d;
+dec $d;
+echo $d;
+let $d=100;
+dec $d;
+echo $d;
+
+let $d=hej;
+echo $d;
+dec $d;
+echo $d;
+
+--error 1
+--exec echo "dec;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "dec i;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "let \$i=100; dec \$i 1000; echo \$i;" | $MYSQL_TEST 2>&1
+
+
+# ----------------------------------------------------------------------------
+# Test system
+# ----------------------------------------------------------------------------
+system ls > /dev/null;
+system echo "hej" > /dev/null;
+--system ls > /dev/null
+--system echo "hej" > /dev/null;
+
+--error 1
+--exec echo "system;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "system NonExistsinfComamdn;" | $MYSQL_TEST 2>&1
+
+--disable_abort_on_error
+system NonExistsinfComamdn;
+--enable_abort_on_error
+
+
+# ----------------------------------------------------------------------------
+# Test delimiter
+# ----------------------------------------------------------------------------
+
+delimiter stop;
+echo teststop
+delimiter ;stop
+echo test2;
+--delimiter stop
+echo test3stop
+--delimiter ;
+echo test4;
+
+# ----------------------------------------------------------------------------
+# Test while, { and }
+# ----------------------------------------------------------------------------
+
+let $i=1;
+while ($i)
+{
+  echo $i;
+  dec $i;
+}
+# One liner
+#let $i=1;while ($i){echo $i;dec $i;}
+
+
+
+# Exceed max nesting level
+--error 1
+--exec echo "source include/mysqltest_while.inc;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "while \$i;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "while (\$i;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "let \$i=1; while (\$i) dec \$i;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "};" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "end;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo "{;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo -e "while (0)\necho hej;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo -e "while (0)\n{echo hej;" | $MYSQL_TEST 2>&1
+--error 1
+--exec echo -e "while (0){\n echo hej;" | $MYSQL_TEST 2>&1
+
+# ----------------------------------------------------------------------------
+# TODO Test queries, especially their errormessages... so it's easy to debug 
+# new scripts and diagnose errors
+# ----------------------------------------------------------------------------
+
+

--- 1.6/mysql-test/t/ndb_autodiscover2.test	2005-04-19 17:23:00 +02:00
+++ 1.7/mysql-test/t/ndb_autodiscover2.test	2005-07-15 17:51:38 +02:00
@@ -6,7 +6,7 @@
 # The previous step has simply removed the frm file
 # from disk, but left the table in NDB
 #
---sleep 3;
+--sleep 3
 select * from t9 order by a;
 
 # handler_discover should be 1

--- 1.6/mysql-test/t/innodb-lock.test	2005-03-30 02:10:40 +02:00
+++ 1.7/mysql-test/t/innodb-lock.test	2005-07-15 17:51:38 +02:00
@@ -39,7 +39,7 @@
 # The following statement should hang because con1 is locking the page
 --send
 lock table t1 write;
---sleep 2;
+--sleep 2
 
 connection con1;
 update t1 set x=1 where id = 0;

--- 1.15/mysql-test/r/rpl_flush_log_loop.result	2004-06-09 16:06:56 +02:00
+++ 1.16/mysql-test/r/rpl_flush_log_loop.result	2005-07-15 17:51:38 +02:00
@@ -4,10 +4,10 @@
 reset slave;
 drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
 start slave;
+stop slave;
 change master to master_host='127.0.0.1',master_user='root',
 master_password='',master_port=MASTER_PORT;
 start slave;
-stop slave;
 change master to master_host='127.0.0.1',master_user='root',
 master_password='',master_port=SLAVE_PORT;
 start slave;

--- 1.6/mysql-test/t/innodb-deadlock.test	2005-03-30 02:10:40 +02:00
+++ 1.7/mysql-test/t/innodb-deadlock.test	2005-07-15 17:51:38 +02:00
@@ -25,7 +25,7 @@
 # The following query should hang because con1 is locking the page
 --send
 update t1 set x=2 where id = 0;
---sleep 2;
+--sleep 2
 
 connection con1;
 update t1 set x=1 where id = 0;
@@ -63,7 +63,7 @@
 # The following query should hang because con1 is locking the page
 --send
 update t1 set x=2 where id = 0;
---sleep 2;
+--sleep 2
 
 connection con1;
 update t1 set x=1 where id = 0;
@@ -97,7 +97,7 @@
 select * from t2;
 --send
 update t1 set x=2 where id = 0;
---sleep 2;
+--sleep 2
 
 connection con1;
 update t1 set x=1 where id = 0;

--- 1.7/mysql-test/t/rpl_flush_log_loop.test	2004-03-20 11:29:41 +01:00
+++ 1.8/mysql-test/t/rpl_flush_log_loop.test	2005-07-15 17:51:38 +02:00
@@ -1,15 +1,15 @@
 # Testing if "flush logs" command bouncing resulting in logs created in a loop 
 # in case of bi-directional replication
 
-source include/master-slave.inc
+source include/master-slave.inc;
 
 connection slave;
+stop slave;
 --replace_result $MASTER_MYPORT MASTER_PORT
 eval change master to master_host='127.0.0.1',master_user='root',
  master_password='',master_port=$MASTER_MYPORT;
 start slave;
 connection master;
-stop slave;
 --replace_result $SLAVE_MYPORT SLAVE_PORT
 eval change master to master_host='127.0.0.1',master_user='root',
  master_password='',master_port=$SLAVE_MYPORT;

--- 1.8/mysql-test/t/rpl_insert_id.test	2005-02-23 19:54:12 +01:00
+++ 1.9/mysql-test/t/rpl_insert_id.test	2005-07-15 17:51:38 +02:00
@@ -4,7 +4,7 @@
 # We also check how the foreign_key_check variable is replicated
 
 source include/master-slave.inc;
-source include/have_innodb.inc
+source include/have_innodb.inc;
 connection master;
 create table t1(a int auto_increment, key(a));
 create table t2(b int auto_increment, c int, key(b));
--- New file ---
+++ mysql-test/include/mysqltest_while.inc	05/07/15 17:51:38
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;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}


--- 1.169/client/mysqltest.c	2005-07-01 15:40:23 +02:00
+++ 1.170/client/mysqltest.c	2005-07-15 17:51:37 +02:00
@@ -42,7 +42,7 @@
 
 **********************************************************************/
 
-#define MTEST_VERSION "2.4"
+#define MTEST_VERSION "2.5"
 
 #include <my_global.h>
 #include <mysql_embed.h>
@@ -75,7 +75,7 @@
 #define LAZY_GUESS_BUF_SIZE 8192
 #define INIT_Q_LINES	  1024
 #define MIN_VAR_ALLOC	  32
-#define BLOCK_STACK_DEPTH  32
+#define BLOCK_STACK_DEPTH  16
 #define MAX_EXPECTED_ERRORS 10
 #define QUERY_SEND  1
 #define QUERY_REAP  2
@@ -151,6 +151,8 @@
 static const char *load_default_groups[]= { "mysqltest","client",0 };
 static char line_buffer[MAX_DELIMITER], *line_buffer_pos= line_buffer;
 
+static char* file_name_stack[MAX_INCLUDE_DEPTH];
+static int cur_file_name;
 static FILE* file_stack[MAX_INCLUDE_DEPTH];
 static FILE** cur_file;
 static FILE** file_stack_end;
@@ -307,7 +309,7 @@
   "connect",
   /* the difference between sleep and real_sleep is that sleep will use
      the delay from command line (--sleep) if there is one.
-     real_sleep always uses delay from it's argument.
+     real_sleep always uses delay from mysqltest's command line argument.
      the logic is that sometimes delays are cpu-dependent (and --sleep
      can be used to set this delay. real_sleep is used for cpu-independent
      delays
@@ -514,6 +516,9 @@
   {
     if (*cur_file != stdin && *cur_file)
       my_fclose(*cur_file,MYF(0));
+    char* p= file_name_stack[cur_file_name--]= 0;
+    if (p)
+      free(p);
   }
   DBUG_VOID_RETURN;
 }
@@ -564,6 +569,10 @@
   if (fmt)
   {
     fprintf(stderr, "%s: ", my_progname);
+    if (*cur_file && cur_file > (file_stack + 1)  )
+      fprintf(stderr, "In included file \"%s\": ",
+              file_name_stack[cur_file_name]);
+    fprintf(stderr, "At line %u: ", start_lineno);
     vfprintf(stderr, fmt, args);
     fprintf(stderr, "\n");
     fflush(stderr);
@@ -809,11 +818,38 @@
 
   if (*cur_file && cur_file == file_stack_end)
     die("Source directives are nesting too deep");
-  if (!(*(cur_file+1) = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME))))
-    die(NullS);
-  cur_file++;
+  if (!(*++cur_file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
+    die("Could not open file %s", buff);
   *++lineno=1;
+  file_name_stack[++cur_file_name]= strdup(buff);
+  return 0;
+}
+
+
+/*
+  Check for unexpected "junk" after the end of query
+  This is normally caused by missing delimiters
+*/
+
+int check_eol_junk(const char *eol)
+{
+  char *p= (char*)eol;
+  /* Remove all spacing chars except new line */
+  while (*p && my_isspace(charset_info,*p) && (*p != '\n'))
+    p++;
 
+  /* Check for extra delimiter */
+  size_t l= strlen(delimiter);
+  if (*p && strlen(p) >= l && !strncmp(p, delimiter, l) )
+    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);
+  }
   return 0;
 }
 
@@ -844,24 +880,26 @@
       break;
     my_sleep(SLAVE_POLL_INTERVAL);
   }
-  return 0;
+  return check_eol_junk(q->first_argument);
 }
 
-int do_require_manager(struct st_query* a __attribute__((unused)))
+int do_require_manager(struct st_query* q)
 {
   if (!manager)
     abort_not_supported_test();
-  return 0;
+  return check_eol_junk(q->first_argument);
 }
 
 #ifndef EMBEDDED_LIBRARY
 int do_server_start(struct st_query* q)
 {
+  check_eol_junk(q->first_argument);
   return do_server_op(q,"start");
 }
 
 int do_server_stop(struct st_query* q)
 {
+  check_eol_junk(q->first_argument);
   return do_server_op(q,"stop");
 }
 
@@ -876,7 +914,7 @@
   com_p=strmov(com_buf,op);
   com_p=strmov(com_p,"_exec ");
   if (!*p)
-    die("Missing server name in server_%s\n",op);
+    die("Missing server name in server_%s",op);
   while (*p && !my_isspace(charset_info,*p))
    *com_p++= *p++;
   *com_p++=' ';
@@ -892,23 +930,42 @@
 	  manager->last_errno);
   }
 
-  return 0;
+  return check_eol_junk(p);
 }
 #endif
 
+
+/*
+  Source and execute the given file
+
+  SYNOPSIS
+    do_source()
+    q	called command
+
+  DESCRIPTION
+    source <file_name>
+
+    Open the file <file_name> and execute it
+
+*/
+
 int do_source(struct st_query* q)
 {
   char* p=q->first_argument, *name;
   if (!*p)
-    die("Missing file name in source\n");
+    die("Missing file name in source");
   name = p;
   while (*p && !my_isspace(charset_info,*p))
     p++;
-  *p = 0;
-
+  if (*p)
+  {
+    *p++= 0;
+    check_eol_junk(p);
+  }
   return open_file(name);
 }
 
+
 /*
   Execute given command.
 
@@ -917,18 +974,19 @@
     q	called command
 
   DESCRIPTION
-    If one uses --exec command [args] command in .test file
-    we will execute the command and record its output.
+    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.
 
-  RETURN VALUES
-    0	ok
-    1	error
 */
 
 static void do_exec(struct st_query* q)
 {
   int error;
-  DYNAMIC_STRING *ds= NULL;			/* Assign just to avoid warning */
+  DYNAMIC_STRING *ds= NULL;
   DYNAMIC_STRING ds_tmp;
   char buf[1024];
   FILE *res_file;
@@ -938,12 +996,12 @@
   while (*cmd && my_isspace(charset_info, *cmd))
     cmd++;
   if (!*cmd)
-    die("Missing argument in exec\n");
+    die("Missing argument in exec");
 
   DBUG_PRINT("info", ("Executing '%s'", cmd));
 
   if (!(res_file= popen(cmd, "r")) && q->abort_on_error)
-    die("popen() failed\n");
+    die("popen(\"%s\", \"r\") failed", cmd);
 
   if (disable_result_log)
   {
@@ -969,34 +1027,36 @@
   error= pclose(res_file);
   if (error != 0)
   {
-    uint status= WEXITSTATUS(error), i;
+    uint i, status= WEXITSTATUS(error);
     my_bool ok= 0;
 
     if (q->abort_on_error)
-      die("At line %u: command \"%s\" failed", start_lineno, cmd);
+      die("command \"%s\" failed", cmd);
 
     DBUG_PRINT("info",
                ("error: %d, status: %d", error, status));
-    for (i=0 ; (uint) i < q->expected_errors ; i++)
+    for (i=0 ; i < q->expected_errors ; i++)
     {
       DBUG_PRINT("info", ("expected error: %d",
                           q->expected_errno[i].code.errnum));
       if ((q->expected_errno[i].type == ERR_ERRNO) &&
           (q->expected_errno[i].code.errnum == status))
+      {
         ok= 1;
-      verbose_msg("At line %u: command \"%s\" failed with expected error: %d",
-                  start_lineno, cmd, status);
+        verbose_msg("command \"%s\" failed with expected error: %d",
+                    cmd, status);
+      }
     }
     if (!ok)
-      die("At line: %u: command \"%s\" failed with wrong error: %d",
-          start_lineno, cmd, status);
+      die("command \"%s\" failed with wrong error: %d",
+          cmd, status);
   }
   else if (q->expected_errno[0].type == ERR_ERRNO &&
            q->expected_errno[0].code.errnum != 0)
   {
     /* Error code we wanted was != 0, i.e. not an expected success */
-    die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...",
-        start_lineno, cmd, q->expected_errno[0].code.errnum);
+    die("command \"%s\" succeeded - should have failed with errno %d...",
+        cmd, q->expected_errno[0].code.errnum);
   }
 
   if (!disable_result_log)
@@ -1007,7 +1067,7 @@
     if (record)
     {
       if (!q->record_file[0] && !result_file)
-        die("At line %u: Missing result file", start_lineno);
+        die("Missing result file");
       if (!result_file)
         str_to_file(q->record_file, ds->str, ds->length);
     }
@@ -1125,26 +1185,67 @@
   return 1;
 }
 
+
+/*
+  Increase the value of a variable
+
+  SYNOPSIS
+    do_inc()
+    q	called command
+
+  DESCRIPTION
+    inc $var_name
+
+*/
+
 int do_inc(struct st_query* q)
 {
   char* p=q->first_argument;
   VAR* v;
+  if (!*p)
+    die("Missing arguments to inc");
+  if (*p != '$')
+    die("First argument to inc must be a variable (start with $)");
   v = var_get(p, 0, 1, 0);
   v->int_val++;
   v->int_dirty = 1;
+  while (*p && !my_isspace(charset_info,*p))
+    p++;
+  check_eol_junk(p);
   return 0;
 }
 
+
+/*
+  Decrease the value of a variable
+
+  SYNOPSIS
+    do_dec()
+    q	called command
+
+  DESCRIPTION
+    dec $var_name
+
+*/
+
 int do_dec(struct st_query* q)
 {
   char* p=q->first_argument;
   VAR* v;
+  if (!*p)
+    die("Missing arguments to dec");
+  if (*p != '$')
+    die("First argument to dec must be a variable (start with $)");
   v = var_get(p, 0, 1, 0);
   v->int_val--;
   v->int_dirty = 1;
+  while (*p && !my_isspace(charset_info,*p))
+    p++;
+  check_eol_junk(p);
   return 0;
 }
 
+
 int do_system(struct st_query* q)
 {
   char* p=q->first_argument;
@@ -1159,26 +1260,63 @@
     memcpy(expr_buf, v.str_val, v.str_val_len);
     expr_buf[v.str_val_len] = 0;
     DBUG_PRINT("info", ("running system command '%s'", expr_buf));
-    if (system(expr_buf) && q->abort_on_error)
-      die("system command '%s' failed", expr_buf);
+    if (system(expr_buf))
+    {
+      if (q->abort_on_error)
+        die("system command '%s' failed", expr_buf);
+      /* If ! abort_on_error, display message and continue */
+      verbose_msg("system command '%s' failed", expr_buf);
+    }
   }
+  else
+    die("Missing arguments to system, nothing to do!");
   var_free(&v);
   return 0;
 }
 
+
+/*
+  Print the content between echo and <delimiter> to result file.
+  If content is a variable, the variable value will be retrieved
+
+  SYNOPSIS
+    do_echo()
+    q  called command
+
+  DESCRIPTION
+    Usage 1:
+    echo text
+    Print the text after echo until end of command to result file
+
+    Usage 2:
+    echo $<var_name>
+    Print the content of the variable <var_name> to result file
+
+*/
+
 int do_echo(struct st_query* q)
 {
   char* p=q->first_argument;
+  DYNAMIC_STRING *ds= NULL;
+  DYNAMIC_STRING ds_tmp;
   VAR v;
   var_init(&v,0,0,0,0);
-  eval_expr(&v, p, 0); /* NULL terminated */
-  if (v.str_val_len)
+
+  if (q->record_file[0])
   {
-    fflush(stdout);
-    write(1, v.str_val, v.str_val_len);
+    init_dynamic_string(&ds_tmp, "", 256, 512);
+    ds = &ds_tmp;
   }
-  write(1, "\n", 1);
+  else
+    ds= &ds_res;
+
+  eval_expr(&v, p, 0); /* NULL terminated */
+  if (v.str_val_len)
+    dynstr_append_mem(ds, v.str_val, v.str_val_len);
+  dynstr_append_mem(ds, "\n", 1);
   var_free(&v);
+  if (ds == &ds_tmp)
+    dynstr_free(&ds_tmp);
   return 0;
 }
 
@@ -1199,8 +1337,19 @@
   rpl_parse = mysql_rpl_parse_enabled(mysql);
   mysql_disable_rpl_parse(mysql);
 
-  if (*p)
-    offset = atoi(p);
+  const char* offset_str= p;
+  /* Step until end of integer arg and check it */
+  while (*p && !my_isspace(charset_info, *p))
+  {
+    if (!my_isdigit(charset_info, *p))
+      die("Invalid integer argument \"%s\"", offset_str);
+    p++;
+  }
+  check_eol_junk(p);
+
+  if (*offset_str)
+    offset = atoi(offset_str);
+
 
   sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
 	  master_pos.pos + offset);
@@ -1256,7 +1405,7 @@
   mysql_disable_rpl_parse(mysql);
 
   if (mysql_query(mysql, query= "show master status"))
-    die("At line %u: failed in show master status: %d: %s", start_lineno,
+    die("failed in show master status: %d: %s",
 	mysql_errno(mysql), mysql_error(mysql));
 
   if (!(last_result =res = mysql_store_result(mysql)))
@@ -1275,20 +1424,52 @@
 }
 
 
+/*
+  Assign the variable <var_name> with <var_val>
+
+  SYNOPSIS
+   do_let()
+    q	called command
+
+  DESCRIPTION
+    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 ;
+
+  RETURN VALUES
+   Program will die if error detected
+*/
+
 int do_let(struct st_query* q)
 {
   char* p=q->first_argument;
   char *var_name, *var_name_end, *var_val_start;
+
+  /* Find <var_name> */
   if (!*p)
-    die("Missing variable name in let\n");
+    die("Missing arguments to let");
   var_name = p;
-  while (*p && (*p != '=' || my_isspace(charset_info,*p)))
+  while (*p && *p != '=' && !my_isspace(charset_info,*p))
     p++;
   var_name_end = p;
-  if (*p == '=') p++;
+  if (var_name+1==var_name_end)
+    die("Missing variable name in let");
+  while (*p && (*p != '=' || my_isspace(charset_info,*p)))
+    p++;
+  if (*p == '=')
+    p++;
+  else
+    die("Missing assignment operator in let");
+
+  /* Find start of <var_val> */
   while (*p && my_isspace(charset_info,*p))
     p++;
   var_val_start = p;
+
+  /* Assign var_val to var_name */
   return var_set(var_name, var_name_end, var_val_start, q->end);
 }
 
@@ -1308,65 +1489,109 @@
 }
 
 
-int do_rpl_probe(struct st_query* q __attribute__((unused)))
+int do_rpl_probe(struct st_query* q)
 {
   DBUG_ENTER("do_rpl_probe");
   if (mysql_rpl_probe(&cur_con->mysql))
     die("Failed in mysql_rpl_probe(): '%s'", mysql_error(&cur_con->mysql));
+  check_eol_junk(q->first_argument);
   DBUG_RETURN(0);
 }
 
 
-int do_enable_rpl_parse(struct st_query* q __attribute__((unused)))
+int do_enable_rpl_parse(struct st_query* q)
 {
   mysql_enable_rpl_parse(&cur_con->mysql);
+  check_eol_junk(q->first_argument);
   return 0;
 }
 
 
-int do_disable_rpl_parse(struct st_query* q __attribute__((unused)))
+int do_disable_rpl_parse(struct st_query* q)
 {
   mysql_disable_rpl_parse(&cur_con->mysql);
+  check_eol_junk(q->first_argument);
   return 0;
 }
 
 
+/*
+  Sleep the number of specifed seconds
+
+  SYNOPSIS
+   do_sleep()
+    q	       called command
+    real_sleep  use the value from opt_sleep as number of seconds to sleep
+
+  DESCRIPTION
+    sleep <seconds>
+    real_sleep
+
+*/
+
 int do_sleep(struct st_query* q, my_bool real_sleep)
 {
   char *p=q->first_argument;
   while (*p && my_isspace(charset_info,*p))
     p++;
   if (!*p)
-    die("Missing argument in sleep\n");
+    die("Missing argument to sleep");
   if (opt_sleep && !real_sleep)
     my_sleep(opt_sleep * 1000000L);
   else
-    my_sleep((ulong) (atof(p) * 1000000L));
-  return 0;
+  {
+    int err= 0;
+    double val=1;
+    const char* val_str= p;
+    while (*p && !my_isspace(charset_info,*p))
+    {
+      if (!my_isdigit(charset_info, *p) && !my_ispunct(charset_info, *p))
+        err= 1;
+      p++;
+    }
+    if (!err)
+      val= my_strtod(val_str, &p, &err);
+    if (err)
+      die("Invalid argument to sleep \"%s\"", q->first_argument);
+    my_sleep((ulong) (val * 1000000L));
+  }
+  return check_eol_junk(p++);
 }
 
 static void get_file_name(char *filename, struct st_query* q)
 {
-  char* p=q->first_argument;
-  strnmov(filename, p, FN_REFLEN);
-  /* Remove end space */
-  while (p > filename && my_isspace(charset_info,p[-1]))
-    p--;
-  p[0]=0;
+
+
+  char* p=q->first_argument, *name;
+  if (!*p)
+    die("Missing file name argument");
+  name = p;
+  while (*p && !my_isspace(charset_info,*p))
+    p++;
+  if (*p)
+  {
+    *p++= 0;
+    check_eol_junk(p);
+  }
+  strmake(filename, name, FN_REFLEN);
 }
 
 static void set_charset(struct st_query* q)
 {
   char* charset_name= q->first_argument;
-  char* tmp;
+  char* p;
 
   if (!charset_name || !*charset_name)
-    die("Missing charset name in 'character_set'\n");
+    die("Missing charset name in 'character_set'");
   /* Remove end space */
-  tmp= charset_name;
-  while (*tmp && !my_isspace(charset_info,*tmp))
-    tmp++;
-  *tmp= 0;
+  p= charset_name;
+  while (*p && !my_isspace(charset_info,*p))
+    p++;
+  if(*p)
+  {
+    *p++= 0;
+    check_eol_junk(p);
+  }
 
   charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME));
   if (!charset_info)
@@ -1380,7 +1605,7 @@
   DBUG_ENTER("get_errcodes");
 
   if (!*p)
-    die("Missing argument in %s\n", q->query);
+    die("Missing argument in %s", q->query);
 
   do
   {
@@ -1399,7 +1624,7 @@
       long val;
       p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val);
       if (p == NULL)
-        die("Invalid argument in %s\n", q->query);
+        die("Invalid argument in %s", q->query);
       to[count].code.errnum= (uint) val;
       to[count].type= ERR_ERRNO;
     }
@@ -1467,7 +1692,7 @@
       *to++=c;
   }
   if (*from != ' ' && *from)
-    die("Wrong string argument in %s\n", q->query);
+    die("Wrong string argument in %s", q->query);
 
   while (my_isspace(charset_info,*from))	/* Point to next string */
     from++;
@@ -1513,14 +1738,14 @@
   bzero((char*) &to_array,sizeof(to_array));
   bzero((char*) &from_array,sizeof(from_array));
   if (!*from)
-    die("Missing argument in %s\n", q->query);
+    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 in %s\n", q->query);
+      die("Wrong number of arguments to replace in %s", q->query);
     insert_pointer_name(&from_array,to);
     to=get_string(&buff, &from, q);
     insert_pointer_name(&to_array,to);
@@ -1534,7 +1759,7 @@
 				  (uint) from_array.typelib.count,
 				  word_end_chars)) ||
       initialize_replace_buffer())
-    die("Can't initialize replace from %s\n", q->query);
+    die("Can't initialize replace from %s", q->query);
   free_pointer_array(&from_array);
   free_pointer_array(&to_array);
   my_free(start, MYF(0));
@@ -1561,11 +1786,16 @@
   DBUG_PRINT("enter",("name: '%s'",p));
 
   if (!*p)
-    die("Missing connection name in connect\n");
+    die("Missing connection name in connect");
   name = p;
   while (*p && !my_isspace(charset_info,*p))
     p++;
-  *p = 0;
+
+  if (*p)
+  {
+    *p++= 0;
+    check_eol_junk(p);
+  }
 
   for (con = cons; con < next_con; con++)
   {
@@ -1587,11 +1817,16 @@
   DBUG_PRINT("enter",("name: '%s'",p));
 
   if (!*p)
-    die("Missing connection name in connect\n");
+    die("Missing connection name in connect");
   name = p;
   while (*p && !my_isspace(charset_info,*p))
     p++;
-  *p = 0;
+
+  if (*p)
+  {
+    *p++= 0;
+    check_eol_junk(p);
+  }
 
   for (con = cons; con < next_con; con++)
   {
@@ -1723,6 +1958,7 @@
       con_sock[var_sock->str_val_len] = 0;
     }
   }
+  check_eol_junk(p);
 
   if (next_con == cons_end)
     die("Connection limit exhausted - increase MAX_CONS in mysqltest.c");
@@ -1783,7 +2019,8 @@
     cur_block--;
     parser.current_line++;
   }
-  return 0;
+  return check_eol_junk(q->first_argument);
+;
 }
 
 
@@ -1817,6 +2054,15 @@
   expr_end = strrchr(expr_start, ')');
   if (!expr_end)
     die("missing ')' in while");
+  p= (char*)expr_end+1;
+
+  while (*p && my_isspace(charset_info, *p))
+    p++;
+  if (*p=='{')
+    die("Missing newline between while and '{'");
+  if (*p)
+    die("Missing '{' after while. Found \"%s\"", p);
+
   var_init(&v,0,0,0,0);
   eval_expr(&v, ++expr_start, &expr_end);
 
@@ -1877,6 +2123,30 @@
 }
 
 
+/*
+  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
+
+  DESCRIPTION
+    This function actually reads several lines an adds them to the
+    buffer buf. It will continue 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 sorrounded 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.
+
+*/
+
 int read_line(char* buf, int size)
 {
   int c;
@@ -1898,9 +2168,23 @@
       if ((*cur_file) != stdin)
 	my_fclose(*cur_file, MYF(0));
       cur_file--;
+      char* p= file_name_stack[cur_file_name--]= 0;
+      if (p)
+        free(p);
       lineno--;
+      start_lineno= *lineno;
       if (cur_file == file_stack)
+      {
+        /* We're back at the first file, check if
+           all { have matching }
+         */
+        if (cur_block != block_stack)
+        {
+          start_lineno= *(lineno+1);
+          die("Missing end of block");
+        }
 	DBUG_RETURN(1);
+      }
       continue;
     }
 
@@ -1933,7 +2217,8 @@
       }
       break;
     case R_LINE_START:
-      if (c == '#' || c == '-')
+      /* Only accept start of comment if this is the first line in query */
+      if ((*lineno == start_lineno) && (c == '#' || c == '-'))
       {
 	state = R_COMMENT;
       }
@@ -2044,6 +2329,26 @@
   DBUG_RETURN(feof(*cur_file));
 }
 
+/*
+  Create a query from a set of lines
+
+  SYNOPSIS
+    q_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.
+
+    If the line starts with !$<num> or !S<alphanum> the query is setup
+    to expect that result when query is executed.
+
+    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.
+
+    If query starts with @<file_name> this will specify a file to ....
+*/
 
 static char read_query_buf[MAX_QUERY];
 
@@ -2409,7 +2714,7 @@
   {
     len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
     if (len == -1)
-      die("Out of memory in replace\n");
+      die("Out of memory in replace");
     val=out_buff;
   }
   dynstr_append_mem(ds, val, len);
@@ -2541,8 +2846,8 @@
   {
     got_error_on_send= mysql_send_query(mysql, query, query_len);
     if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY)
-      die("At line %u: unable to send query '%s' (mysql_errno=%d , errno=%d)",
-	  start_lineno, query, mysql_errno(mysql), errno);
+      die("unable to send query '%s' (mysql_errno=%d , errno=%d)",
+	  query, mysql_errno(mysql), errno);
   }
 
   do
@@ -2566,7 +2871,7 @@
 	abort_not_supported_test();
       }
       if (q->abort_on_error)
-	die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
+	die("query '%s' failed: %d: %s", query,
 	    mysql_errno(mysql), mysql_error(mysql));
       else
       {
@@ -2653,7 +2958,7 @@
 
     if (!disable_result_log)
     {
-      ulong affected_rows;    /* Ok to be undef if 'disable_info' is set */
+      ulong affected_rows= 0;
 
       if (res)
       {
@@ -2720,7 +3025,7 @@
     if (record)
     {
       if (!q->record_file[0] && !result_file)
-	die("At line %u: Missing result file", start_lineno);
+	die("Missing result file");
       if (!result_file)
 	str_to_file(q->record_file, ds->str, ds->length);
     }
@@ -2782,7 +3087,7 @@
     may be a new connection.
   */
   if (!(stmt= mysql_stmt_init(mysql)))
-    die("At line %u: unable init stmt structure");
+    die("unable init stmt structure");
   
   if (q->type != Q_EVAL)
   {
@@ -2826,9 +3131,9 @@
   {
     if (q->abort_on_error)
     {
-      die("At line %u: unable to prepare statement '%s': "
+      die("unable to prepare statement '%s': "
           "%s (mysql_stmt_errno=%d returned=%d)",
-          start_lineno, query,
+          query,
           mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
     }
     else
@@ -2860,9 +3165,9 @@
     if (q->abort_on_error)
     {
       /* We got an error, unexpected */
-      die("At line %u: unable to execute statement '%s': "
+      die("unable to execute statement '%s': "
           "%s (mysql_stmt_errno=%d returned=%d)",
-          start_lineno, query, mysql_stmt_error(stmt),
+          query, mysql_stmt_error(stmt),
           mysql_stmt_errno(stmt), got_error_on_execute);
     }
     else
@@ -2882,9 +3187,9 @@
     my_bool one= 1;
     if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH,
                             (void*) &one) != 0)
-      die("At line %u: unable to set stmt attribute "
+      die("unable to set stmt attribute "
           "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)",
-          start_lineno, query, err);
+          query, err);
   }
 
   /*
@@ -2896,9 +3201,9 @@
     if (q->abort_on_error)
     {
       /* We got an error, unexpected */
-      die("At line %u: unable to execute statement '%s': "
+      die("unable to execute statement '%s': "
           "%s (mysql_stmt_errno=%d returned=%d)",
-          start_lineno, query, mysql_stmt_error(stmt),
+          query, mysql_stmt_error(stmt),
           mysql_stmt_errno(stmt), got_error_on_execute);
     }
     else
@@ -2989,18 +3294,18 @@
 
       /* Fill in the data into the structures created above */
       if ((err= mysql_stmt_bind_result(stmt, bind)) != 0)
-        die("At line %u: unable to bind result to statement '%s': "
+        die("unable to bind result to statement '%s': "
             "%s (mysql_stmt_errno=%d returned=%d)",
-            start_lineno, query,
+            query,
             mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
 
       /* Read result from each row */
       for (row_idx= 0; row_idx < num_rows; row_idx++)
       {
         if ((err= mysql_stmt_fetch(stmt)) != 0)
-          die("At line %u: unable to fetch all rows from statement '%s': "
+          die("unable to fetch all rows from statement '%s': "
               "%s (mysql_stmt_errno=%d returned=%d)",
-              start_lineno, query,
+              query,
               mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
 
         /* Read result from each column */
@@ -3038,9 +3343,9 @@
       }
 
       if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA)
-        die("At line %u: fetch didn't end with MYSQL_NO_DATA from statement "
+        die("fetch didn't end with MYSQL_NO_DATA from statement "
             "'%s': %s (mysql_stmt_errno=%d returned=%d)",
-            start_lineno, query,
+            query,
             mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err);
 
       free_replace_column();
@@ -3077,7 +3382,7 @@
   if (record)
   {
     if (!q->record_file[0] && !result_file)
-      die("At line %u: Missing result file", start_lineno);
+      die("Missing result file");
     if (!result_file)
       str_to_file(q->record_file, ds->str, ds->length);
   }
@@ -3198,7 +3503,7 @@
   }
 
   if (q->abort_on_error)
-    die("At line %u: query '%s' failed: %d: %s", start_lineno, query,
+    die("query '%s' failed: %d: %s", query,
         mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
   else
   {
@@ -3438,7 +3743,7 @@
   struct st_query *q;
   my_bool require_file=0, q_send_flag=0;
   char save_file[FN_REFLEN];
-  MY_INIT(argv[0]);
+  MY_INIT("mysqltest");
   {
   DBUG_ENTER("main");
   DBUG_PROCESS(argv[0]);
@@ -3454,15 +3759,16 @@
   cur_con = cons;
 
   memset(file_stack, 0, sizeof(file_stack));
+  memset(file_name_stack, 0, sizeof(file_name_stack));
   memset(&master_pos, 0, sizeof(master_pos));
-  file_stack_end = file_stack + MAX_INCLUDE_DEPTH;
+  file_stack_end = file_stack + MAX_INCLUDE_DEPTH - 1;
   cur_file = file_stack;
   lineno   = lineno_stack;
   my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES,
 		     INIT_Q_LINES);
 
   memset(block_stack, 0, sizeof(block_stack));
-  block_stack_end= block_stack + BLOCK_STACK_DEPTH;
+  block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1;
   cur_block= block_stack;
   cur_block->ok= TRUE; /* Outer block should always be executed */
   cur_block->cmd= Q_UNKNOWN;
@@ -3474,7 +3780,10 @@
 			(char**) embedded_server_groups))
     die("Can't initialize MySQL server");
   if (cur_file == file_stack)
-    *++cur_file = stdin;
+  {
+    *++cur_file= stdin;
+    ++cur_file_name;
+  }
   *lineno=1;
 #ifndef EMBEDDED_LIBRARY
   if (manager_host)
@@ -3530,18 +3839,30 @@
       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;
-      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;
-      case Q_DISABLE_ABORT_ON_ERROR: abort_on_error=0; break;
-      case Q_ENABLE_RESULT_LOG:  disable_result_log=0; break;
-      case Q_DISABLE_RESULT_LOG: disable_result_log=1; break;
-      case Q_ENABLE_WARNINGS:    disable_warnings=0; break;
-      case Q_DISABLE_WARNINGS:   disable_warnings=1; break;
-      case Q_ENABLE_INFO:        disable_info=0; break;
-      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_ENABLE_QUERY_LOG:
+        disable_query_log=0; check_eol_junk(q->first_argument); break;
+      case Q_DISABLE_QUERY_LOG:
+        disable_query_log=1; check_eol_junk(q->first_argument); break;
+      case Q_ENABLE_ABORT_ON_ERROR:
+        abort_on_error=1; check_eol_junk(q->first_argument); break;
+      case Q_DISABLE_ABORT_ON_ERROR:
+        abort_on_error=0; check_eol_junk(q->first_argument); break;
+      case Q_ENABLE_RESULT_LOG:
+        disable_result_log=0; check_eol_junk(q->first_argument); break;
+      case Q_DISABLE_RESULT_LOG:
+        disable_result_log=1; check_eol_junk(q->first_argument); break;
+      case Q_ENABLE_WARNINGS:
+        disable_warnings=0; check_eol_junk(q->first_argument); break;
+      case Q_DISABLE_WARNINGS:
+        disable_warnings=1; check_eol_junk(q->first_argument); break;
+      case Q_ENABLE_INFO:
+        disable_info=0; check_eol_junk(q->first_argument); break;
+      case Q_DISABLE_INFO:
+        disable_info=1; check_eol_junk(q->first_argument); break;
+      case Q_ENABLE_METADATA:
+        display_metadata=1; check_eol_junk(q->first_argument); break;
+      case Q_DISABLE_METADATA:
+        display_metadata=0; check_eol_junk(q->first_argument); 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;
@@ -3558,12 +3879,19 @@
       case Q_DELIMITER:
 	strmake(delimiter, q->first_argument, sizeof(delimiter) - 1);
 	delimiter_length= strlen(delimiter);
+        check_eol_junk(q->first_argument+delimiter_length);
 	break;
-      case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; break;
-      case Q_DISPLAY_HORIZONTAL_RESULTS: 
-	display_result_vertically= FALSE; break;
+      case Q_DISPLAY_VERTICAL_RESULTS:
+        display_result_vertically= TRUE;
+        check_eol_junk(q->first_argument);
+        break;
+      case Q_DISPLAY_HORIZONTAL_RESULTS:
+	display_result_vertically= FALSE;
+        check_eol_junk(q->first_argument);
+        break;
       case Q_LET: do_let(q); break;
-      case Q_EVAL_RESULT: eval_result = 1; break;
+      case Q_EVAL_RESULT:
+        eval_result = 1; check_eol_junk(q->first_argument); break;
       case Q_EVAL:
 	if (q->query == q->query_buf)
         {
@@ -3677,33 +4005,40 @@
 	break;
       case Q_PING:
 	(void) mysql_ping(&cur_con->mysql);
+        check_eol_junk(q->first_argument);
 	break;
-      case Q_EXEC: 
+      case Q_EXEC:
 	do_exec(q);
 	break;
       case Q_START_TIMER:
 	/* Overwrite possible earlier start of timer */
 	timer_start= timer_now();
+        check_eol_junk(q->first_argument);
 	break;
       case Q_END_TIMER:
 	/* End timer before ending mysqltest */
 	timer_output();
 	got_end_timer= TRUE;
+        check_eol_junk(q->first_argument);
 	break;
-      case Q_CHARACTER_SET: 
+      case Q_CHARACTER_SET:
 	set_charset(q);
 	break;
       case Q_DISABLE_PS_PROTOCOL:
         ps_protocol_enabled= 0;
+        check_eol_junk(q->first_argument);
         break;
       case Q_ENABLE_PS_PROTOCOL:
         ps_protocol_enabled= ps_protocol;
+        check_eol_junk(q->first_argument);
         break;
       case Q_DISABLE_RECONNECT:
         cur_con->mysql.reconnect= 0;
+        check_eol_junk(q->first_argument);
         break;
       case Q_ENABLE_RECONNECT:
         cur_con->mysql.reconnect= 1;
+        check_eol_junk(q->first_argument);
         break;
 
       default: processed = 0; break;
@@ -3724,7 +4059,7 @@
     parser.current_line += current_line_inc;
   }
 
-  if (result_file && ds_res.length)
+  if (result_file && ds_res.length && !error)
   {
     if (!record)
       error |= check_result(&ds_res, result_file, q->require_file);
@@ -4584,7 +4919,7 @@
 
   free_replace_column();
   if (!*from)
-    die("Missing argument in %s\n", q->query);
+    die("Missing argument in %s", q->query);
 
   /* Allocate a buffer for results */
   start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE));
@@ -4595,9 +4930,9 @@
 
     to= get_string(&buff, &from, q);
     if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS)
-      die("Wrong column number to replace_columns in %s\n", q->query);
+      die("Wrong column number to replace_columns in %s", q->query);
     if (!*from)
-      die("Wrong number of arguments to replace in %s\n", q->query);
+      die("Wrong number of arguments to replace 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));
@@ -4654,7 +4989,7 @@
       if (!(subst= getenv(env_var)))
       {
         my_free(result, MYF(0));
-        die("MYSQLTEST.NLM: Environment variable %s is not defined\n",
+        die("MYSQLTEST.NLM: Environment variable %s is not defined",
             env_var);
       }
 

--- 1.50/mysql-test/t/rpl_rotate_logs.test	2004-11-22 20:13:40 +01:00
+++ 1.51/mysql-test/t/rpl_rotate_logs.test	2005-07-15 17:51:38 +02:00
@@ -102,7 +102,7 @@
 purge binary logs to 'master-bin.000002';
 show binary logs;
 # sleeping 10 seconds or more would make the slave believe connection is down
---real_sleep 1;
+--real_sleep 1
 purge master logs before now();
 show binary logs;
 insert into t2 values (65);
Thread
bk commit into 4.1 tree (msvensson:1.2327) BUG#11316msvensson15 Jul