From: Bjorn Munch Date: November 8 2010 2:15pm Subject: bzr commit into mysql-5.5-mtr branch (bjorn.munch:3110) Bug#57276 List-Archive: http://lists.mysql.com/commits/123087 X-Bug: 57276 Message-Id: <201011081415.oA8EFWB6028205@khepri15.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1283878307==" --===============1283878307== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/bm136801/my/ifexpr-55/ based on revid:bjorn.munch@stripped 3110 Bjorn Munch 2010-11-08 Bug #57276 mysqltest: add support for simple compares in if/while conditions Added more parsing in do_block() Limitations: left operand must be variable, white space must surround operator Also changed var_set_int from 57036 to var_check_int Added tests to mysqltest.test Some tests can now be simplified but will take this later (This is a recommit of the first patch) modified: client/mysqltest.cc mysql-test/r/mysqltest.result mysql-test/t/mysqltest.test === modified file 'client/mysqltest.cc' --- a/client/mysqltest.cc 2010-10-21 09:20:53 +0000 +++ b/client/mysqltest.cc 2010-11-08 14:13:45 +0000 @@ -482,7 +482,8 @@ VAR* var_init(VAR* v, const char *name, int val_len); 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); +void eval_expr(VAR* v, const char *p, const char** p_end, + my_bool open_end=FALSE); my_bool match_delimiter(int c, const char *delim, uint length); void dump_result_to_reject_file(char *buf, int size); void dump_warning_messages(); @@ -2040,9 +2041,11 @@ static void var_free(void *v) C_MODE_END -void var_set_int(VAR *v, const char *str) +void var_check_int(VAR *v) { char *endptr; + char *str= v->str_val; + /* Initially assume not a number */ v->int_val= 0; v->is_int= false; @@ -2089,7 +2092,7 @@ VAR *var_init(VAR *v, const char *name, memcpy(tmp_var->str_val, val, val_len); tmp_var->str_val[val_len]= 0; } - var_set_int(tmp_var, val); + var_check_int(tmp_var); tmp_var->name_len = name_len; tmp_var->str_val_len = val_len; tmp_var->alloced_len = val_alloc_len; @@ -2540,7 +2543,7 @@ void var_copy(VAR *dest, VAR *src) } -void eval_expr(VAR *v, const char *p, const char **p_end) +void eval_expr(VAR *v, const char *p, const char **p_end, my_bool open_end) { DBUG_ENTER("eval_expr"); @@ -2558,7 +2561,7 @@ void eval_expr(VAR *v, const char *p, co /* Make sure there was just a $variable and nothing else */ const char* end= *p_end + 1; - if (end < expected_end) + if (end < expected_end && !open_end) die("Found junk '%.*s' after $variable in expression", (int)(expected_end - end - 1), end); @@ -2605,7 +2608,7 @@ void eval_expr(VAR *v, const char *p, co v->str_val_len = new_val_len; memcpy(v->str_val, p, new_val_len); v->str_val[new_val_len] = 0; - var_set_int(v, p); + var_check_int(v); } DBUG_VOID_RETURN; } @@ -5498,6 +5501,40 @@ int do_done(struct st_command *command) return 0; } +/* Operands available in if or while conditions */ + +enum block_op { + EQ_OP, + NE_OP, + GT_OP, + GE_OP, + LT_OP, + LE_OP, + ILLEG_OP +}; + + +enum block_op find_operand(const char *start) +{ + char first= *start; + char next= *(start+1); + + if (first == '=' && next == '=') + return EQ_OP; + if (first == '!' && next == '=') + return NE_OP; + if (first == '>' && next == '=') + return GE_OP; + if (first == '>' && next == ' ') + return GT_OP; + if (first == '<' && next == '=') + return LE_OP; + if (first == '<' && next == ' ') + return LT_OP; + + return ILLEG_OP; +} + /* Process start of a "if" or "while" statement @@ -5523,6 +5560,13 @@ int do_done(struct st_command *command) A '!' can be used before the to indicate it should be executed if it evaluates to zero. + can also be a simple comparison condition: + + + + The left hand side must be a variable, the right hand side can be a + variable, number, string or `query`. Operands are ==, !=, <, <=, >, >=. + == and != can be used for strings, all can be used for numerical values. */ void do_block(enum block_cmd cmd, struct st_command* command) @@ -5558,6 +5602,9 @@ void do_block(enum block_cmd cmd, struct if (!expr_start++) die("missing '(' in %s", cmd_name); + while (my_isspace(charset_info, *expr_start)) + expr_start++; + /* Check for ! */ if (*expr_start == '!') { @@ -5576,14 +5623,84 @@ void do_block(enum block_cmd cmd, struct die("Missing '{' after %s. Found \"%s\"", cmd_name, p); var_init(&v,0,0,0,0); - eval_expr(&v, expr_start, &expr_end); + /* If expression starts with a variable, it may be a compare condition */ + + if (*expr_start == '$') + { + const char *curr_ptr= expr_end; + eval_expr(&v, expr_start, &curr_ptr, TRUE); + while (my_isspace(charset_info, *++curr_ptr)) ; + /* If there was nothing past the variable, skip condition part */ + if (curr_ptr == expr_end) + goto NO_COMPARE; + + enum block_op operand= find_operand(curr_ptr); + if (operand == ILLEG_OP) + die("Found junk '%.*s' after $variable in condition", + (int)(expr_end - curr_ptr), curr_ptr); + + /* We could silently allow this, but may be confusing */ + if (not_expr) + die("Negation and comparison should not be combined, please rewrite"); + + curr_ptr++; + while (my_isspace(charset_info, *++curr_ptr)) ; + + VAR v2; + var_init(&v2,0,0,0,0); + eval_expr(&v2, curr_ptr, &expr_end); + + if ((operand!=EQ_OP && operand!=NE_OP) && ! (v.is_int && v2.is_int)) + die ("Cannot use inequality operand on non-numeric values"); + + /* Now we overwrite the first variable with the value of 0 or 1 */ + + switch (operand) + { + case EQ_OP: + if (v.is_int) + v.int_val= (v2.is_int && v2.int_val == v.int_val); + else + v.int_val= !strcmp (v.str_val, v2.str_val); + break; + + case NE_OP: + if (v.is_int) + v.int_val= ! (v2.is_int && v2.int_val == v.int_val); + else + v.int_val= !! strcmp (v.str_val, v2.str_val); + break; + + case LT_OP: + v.int_val= (v.int_val < v2.int_val); + break; + case LE_OP: + v.int_val= (v.int_val <= v2.int_val); + break; + case GT_OP: + v.int_val= (v.int_val > v2.int_val); + break; + case GE_OP: + v.int_val= (v.int_val >= v2.int_val); + break; + } + + v.is_int= TRUE; + } else + { + if (*expr_start != '`' && ! my_isdigit(charset_info, *expr_start)) + die("Expression in if/while must beging with $, ` or a number"); + eval_expr(&v, expr_start, &expr_end); + } + + NO_COMPARE: /* Define inner block */ cur_block++; cur_block->cmd= cmd; - if (v.int_val) + if (v.is_int) { - cur_block->ok= TRUE; + cur_block->ok= (v.int_val != 0); } else /* Any non-empty string which does not begin with 0 is also TRUE */ { === modified file 'mysql-test/r/mysqltest.result' --- a/mysql-test/r/mysqltest.result 2010-09-28 14:00:11 +0000 +++ b/mysql-test/r/mysqltest.result 2010-11-08 14:13:45 +0000 @@ -401,8 +401,31 @@ true-outer Counter is greater than 0, (counter=10) Counter is not 0, (counter=0) Counter is true, (counter=alpha) -Beta is true while with string, only once +5<7 +5<6 +5>=5 +5>3 +5==5 +5!=8 +5==3+2 +5 == 5 +hello == hello +hello == hello +hello != goodbye +two words +two words are two words +right answer +anything goes +mysqltest: At line 2: Cannot use inequality operand on non-numeric values +mysqltest: At line 2: Found junk '<> 6' after $variable in condition +mysqltest: At line 2: Expression in if/while must beging with $, ` or a number +counter is 2 +counter is 3 +counter is 4 +counter is 5 +counter is 6 +counter is 7 1 Testing while with not mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest_while.inc": At line 64: Nesting too deeply @@ -807,8 +830,6 @@ dir-list.txt SELECT 'c:\\a.txt' AS col; col z -hej -mysqltest: At line 1: Found junk ' != 143' after $variable in expression select 1; 1 1 === modified file 'mysql-test/t/mysqltest.test' --- a/mysql-test/t/mysqltest.test 2010-10-19 12:13:05 +0000 +++ b/mysql-test/t/mysqltest.test 2010-11-08 14:13:45 +0000 @@ -1163,10 +1163,11 @@ if ($counter) { echo oops, -0 is true; } -if (beta) -{ - echo Beta is true; -} +# This is no longer allowed, as a precaution against mistyped conditionals +# if (beta) +# { +# echo Beta is true; +# } let $counter=gamma; while ($counter) { @@ -1175,6 +1176,152 @@ while ($counter) } # ---------------------------------------------------------------------------- +# Test if with compare conditions +# ---------------------------------------------------------------------------- + +let $ifvar= 5; +let $ifvar2= 6; + +if ($ifvar < 7) +{ + echo 5<7; +} +if ($ifvar < $ifvar2) +{ + echo 5<6; +} +if ($ifvar <= 4) +{ + echo 5<=4; +} +if ($ifvar >= 5) +{ + echo 5>=5; +} +if ($ifvar > 3) +{ + echo 5>3; +} +if ($ifvar == 4) +{ + echo 5==4; +} +if ($ifvar == 5) +{ + echo 5==5; +} +if ($ifvar != 8) +{ + echo 5!=8; +} +if ($ifvar == `SELECT 3+2`) +{ + echo 5==3+2; +} +if ($ifvar == 5) +{ + echo 5 == 5; +} +let $ifvar= hello; +if ($ifvar == hello there) +{ + echo hello == hello there; +} +if ($ifvar == hello) +{ + echo hello == hello; +} +if ($ifvar == hell) +{ + echo hello == hell; +} +if ($ifvar == hello) +{ + echo hello == hello; +} +if ($ifvar != goodbye) +{ + echo hello != goodbye; +} + +let $ifvar= two words; +if ($ifvar == two words) +{ + echo two words; +} +if ($ifvar == `SELECT 'two words'`) +{ + echo two words are two words; +} +if (42) +{ + echo right answer; +} +if (0) +{ + echo wrong answer; +} +if (`SELECT 'something'`) +{ + echo anything goes; +} + +--write_file $MYSQL_TMP_DIR/mysqltest.sql +let $var= 5; +if ($var >= four) +{ + echo 5>=four; +} +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQL_TMP_DIR/mysqltest.sql 2>&1 +remove_file $MYSQL_TMP_DIR/mysqltest.sql; + +--write_file $MYSQL_TMP_DIR/mysqltest.sql +let $var= 5; +if ($var <> 6) +{ + echo 5<>6; +} +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQL_TMP_DIR/mysqltest.sql 2>&1 +remove_file $MYSQL_TMP_DIR/mysqltest.sql; + +--write_file $MYSQL_TMP_DIR/mysqltest.sql +let $var= text; +if (var == text) +{ + echo Oops I forgot the $; +} +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQL_TMP_DIR/mysqltest.sql 2>&1 +remove_file $MYSQL_TMP_DIR/mysqltest.sql; + +# ---------------------------------------------------------------------------- +# Test while with compare conditions +# ---------------------------------------------------------------------------- + +let $counter= 2; + +while ($counter < 5) +{ + echo counter is $counter; + inc $counter; +} +let $ifvar=; +while ($ifvar != stop) +{ + if ($counter >= 7) + { + let $ifvar= stop; + } + echo counter is $counter; + inc $counter; +} + +# ---------------------------------------------------------------------------- # Test while, { and } # ---------------------------------------------------------------------------- @@ -2529,26 +2676,6 @@ rmdir $MYSQLTEST_VARDIR/tmp/testdir; --replace_result c:\\a.txt z SELECT 'c:\\a.txt' AS col; -# -# Bug#32307 mysqltest - does not detect illegal if syntax -# - -let $test= 1; -if ($test){ - echo hej; -} - ---write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql -if ($mysql_errno != 1436) -{ - echo ^ Should not be allowed! -} -EOF ---error 1 ---exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 -remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql; - - # ---------------------------------------------------------------------------- # Test that -- is not allowed as comment, only as mysqltest builtin command # ---------------------------------------------------------------------------- --===============1283878307== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/bjorn.munch@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: bjorn.munch@stripped # target_branch: file:///home/bm136801/my/ifexpr-55/ # testament_sha1: f666e80c69be9098fd45849936fc84be4f8606b7 # timestamp: 2010-11-08 15:15:32 +0100 # base_revision_id: bjorn.munch@stripped\ # gs9le2clrl7vb6ig # # Begin bundle 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 --===============1283878307==--