diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 10a59b0c4afda..f78b469d1608e 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -4614,9 +4614,12 @@ void do_write_file_command(struct st_command *command, my_bool append) static DYNAMIC_STRING ds_content; static DYNAMIC_STRING ds_filename; static DYNAMIC_STRING ds_delimiter; + static DYNAMIC_STRING ds_eval_flag; + my_bool eval_content; 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" } + { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" }, + { "eval", ARG_STRING, FALSE, &ds_eval_flag, "Evaluate the content" } }; DBUG_ENTER("do_write_file"); @@ -4629,6 +4632,14 @@ void do_write_file_command(struct st_command *command, my_bool append) if (bad_path(ds_filename.str)) DBUG_VOID_RETURN; + if ((eval_content= (ds_eval_flag.length != 0)) && + strcasecmp(ds_eval_flag.str, "eval")) + { + report_or_die("Invalid argument '%s' to '%.*b', only 'eval' is allowed", + ds_eval_flag.str, command->first_word_len, command->query); + DBUG_VOID_RETURN; + } + if (!append && access(ds_filename.str, F_OK) == 0) { /* The file should not be overwritten */ @@ -4651,10 +4662,24 @@ void do_write_file_command(struct st_command *command, my_bool append) if (cur_block->ok) { DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); - str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); + if (eval_content) + { + /* Evaluate on every execution, keep command->content unevaluated */ + DYNAMIC_STRING ds_eval_content; + if (init_dynamic_string(&ds_eval_content, "", ds_content.length + 256, 256)) + die("Out of memory"); + do_eval(&ds_eval_content, ds_content.str, + ds_content.str + ds_content.length, FALSE); + str_to_file2(ds_filename.str, ds_eval_content.str, ds_eval_content.length, + append); + dynstr_free(&ds_eval_content); + } + else + str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append); } dynstr_free(&ds_filename); dynstr_free(&ds_delimiter); + dynstr_free(&ds_eval_flag); DBUG_VOID_RETURN; } @@ -4665,11 +4690,11 @@ void do_write_file_command(struct st_command *command, my_bool append) command called command DESCRIPTION - write_file []; + write_file [ [eval]]; <...> < what to write line n> - EOF + --write_file ; @@ -4680,6 +4705,9 @@ void do_write_file_command(struct st_command *command, my_bool append) Write everything between the "write_file" command and 'delimiter' to "file_name" + If 'eval' is given, variables and expressions in the content are + substituted. It requires to be given explicitly. + NOTE! Will fail if exists Default is EOF @@ -4741,11 +4769,11 @@ void do_write_line(struct st_command *command) command called command DESCRIPTION - append_file []; + append_file [ [eval]]; <...> < what to write line n> - EOF + --append_file ; @@ -4756,6 +4784,9 @@ void do_write_line(struct st_command *command) Append everything between the "append_file" command and 'delimiter' to "file_name" + If 'eval' is given, variables and expressions in the content are + substituted. It requires to be given explicitly. + Default is EOF */ diff --git a/mysql-test/main/mysqltest.result b/mysql-test/main/mysqltest.result index 478ef82ca1fa0..46234ba89a258 100644 --- a/mysql-test/main/mysqltest.result +++ b/mysql-test/main/mysqltest.result @@ -989,4 +989,41 @@ select "foo\""bar"; foo\"bar foo\"bar set sql_mode=default; +# +# MDEV-40353: append_file in mysqltest does not support variables +# and expressions substitution +# +# Without 'eval' the content is written as it is +variable: $var +expression: $(6*7) +escaped: \$var +a backslash: \\! echo foo +undefined variable: $mdev_40353_not_set. +# With 'eval' variables and expressions are substituted +variable: foo +expression: 42 +escaped: $var +a backslash: \! echo foo +undefined variable: . +# a lone dollar sign is an error when evaluated +mysqltest: At line 1: Empty variable +# append_file with 'eval' and a not default delimiter +variable: foo +expression: 42 +escaped: $var +a backslash: \! echo foo +undefined variable: . +appended: foo +# The 'eval' argument is not case sensitive +variable: foo +# The content is evaluated on every execution of the command +iteration 1 +iteration 2 +# Nothing is written and nothing is evaluated in a false block +the false block has written nothing +# 'eval' requires the delimiter to be given explicitly +mysqltest: At line 1: End of file encountered before 'eval' delimiter was found +# Only 'eval' is allowed as the third argument +mysqltest: At line 1: Invalid argument 'junk' to 'write_file', only 'eval' is allowed +# End of 10.6 tests End of tests diff --git a/mysql-test/main/mysqltest.test b/mysql-test/main/mysqltest.test index b545e3540403e..ba01acbf6c6c5 100644 --- a/mysql-test/main/mysqltest.test +++ b/mysql-test/main/mysqltest.test @@ -2954,6 +2954,111 @@ set sql_mode=no_backslash_escapes; select "foo\""bar"; set sql_mode=default; +--echo # +--echo # MDEV-40353: append_file in mysqltest does not support variables +--echo # and expressions substitution +--echo # + +--let $file= $MYSQLTEST_VARDIR/tmp/mdev_40353.txt +--let $var= foo + +--echo # Without 'eval' the content is written as it is + +--write_file $file +variable: $var +expression: $(6*7) +escaped: \$var +a backslash: \\! echo foo +undefined variable: $mdev_40353_not_set. +EOF +--cat_file $file +--remove_file $file + +--echo # With 'eval' variables and expressions are substituted + +--write_file $file EOF eval +variable: $var +expression: $(6*7) +escaped: \$var +a backslash: \\! echo foo +undefined variable: $mdev_40353_not_set. +EOF +--cat_file $file + +--echo # a lone dollar sign is an error when evaluated + +--let $script= $MYSQLTEST_VARDIR/tmp/mdev_40353_err.test +--write_file $script END + --write_file $MYSQLTEST_VARDIR/tmp/mdev_40353_err.txt EOF eval + a lone dollar sign: $ + EOF +END +--error 1 +--exec $MYSQL_TEST < $script 2>&1 +--remove_file $script + +--echo # append_file with 'eval' and a not default delimiter + +--append_file $file END eval +appended: $var +END +--cat_file $file +--remove_file $file + +--echo # The 'eval' argument is not case sensitive + +--write_file $file EOF EVAL +variable: $var +EOF +--cat_file $file +--remove_file $file + +--echo # The content is evaluated on every execution of the command + +--let $i= 0 +while ($i < 2) +{ + --inc $i + --append_file $file EOF eval +iteration $i +EOF +} +--cat_file $file +--remove_file $file + +--echo # Nothing is written and nothing is evaluated in a false block + +# A lone dollar sign in the content would be an error if it was evaluated +--let $i= 0 +while ($i < 1) +{ + --inc $i + if (0) + { + --write_file $file EOF eval +$ +EOF + } +} + +# write_file fails if the file exists, so it also checks that the +# false block above has written nothing +--write_file $file +the false block has written nothing +EOF +--cat_file $file +--remove_file $file + +--echo # 'eval' requires the delimiter to be given explicitly +--error 1 +--exec echo "--write_file $file eval" | $MYSQL_TEST 2>&1 + +--echo # Only 'eval' is allowed as the third argument +--error 1 +--exec echo "--write_file $file EOF junk" | $MYSQL_TEST 2>&1 + +--echo # End of 10.6 tests + --echo End of tests # Wait till we reached the initial number of concurrent sessions