Bug #57276 mysqltest: add support for simple compares in if/while conditions
Added more parsing in do_block() Limitation: left operand must be variable 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 Updated after comments, now white space around operator not needed
This commit is contained in:
parent
e0678e2ca6
commit
3fab294616
@ -482,7 +482,8 @@ VAR* var_init(VAR* v, const char *name, int name_len, const char *val,
|
||||
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,
|
||||
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, int name_len, const char *val,
|
||||
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, bool open_end)
|
||||
{
|
||||
|
||||
DBUG_ENTER("eval_expr");
|
||||
@ -2558,7 +2561,7 @@ void eval_expr(VAR *v, const char *p, const char **p_end)
|
||||
|
||||
/* 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, const char **p_end)
|
||||
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 == '>')
|
||||
return GT_OP;
|
||||
if (first == '<' && next == '=')
|
||||
return LE_OP;
|
||||
if (first == '<')
|
||||
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 <expr> to indicate it should
|
||||
be executed if it evaluates to zero.
|
||||
|
||||
<expr> can also be a simple comparison condition:
|
||||
|
||||
<variable> <op> <expr>
|
||||
|
||||
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 st_command* command)
|
||||
if (!expr_start++)
|
||||
die("missing '(' in %s", cmd_name);
|
||||
|
||||
while (my_isspace(charset_info, *expr_start))
|
||||
expr_start++;
|
||||
|
||||
/* Check for !<expr> */
|
||||
if (*expr_start == '!')
|
||||
{
|
||||
@ -5576,14 +5623,94 @@ void do_block(enum block_cmd cmd, struct st_command* command)
|
||||
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");
|
||||
|
||||
/* Skip the 1 or 2 chars of the operand, then white space */
|
||||
if (operand == LT_OP || operand == GT_OP)
|
||||
{
|
||||
curr_ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_ptr+= 2;
|
||||
}
|
||||
while (my_isspace(charset_info, *curr_ptr))
|
||||
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 ("Only == and != are supported for string values");
|
||||
|
||||
/* Now we overwrite the first variable with 0 or 1 (for false or true) */
|
||||
|
||||
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) != 0);
|
||||
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 */
|
||||
{
|
||||
|
@ -401,8 +401,36 @@ 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<7 again
|
||||
5<7 still
|
||||
5<6
|
||||
5>=5
|
||||
5>=5 again
|
||||
5>3
|
||||
5==5
|
||||
5!=8
|
||||
5!=five
|
||||
5==3+2
|
||||
5 == 5
|
||||
hello == hello
|
||||
hello == hello
|
||||
hello != goodbye
|
||||
two words
|
||||
two words are two words
|
||||
right answer
|
||||
anything goes
|
||||
0 != string
|
||||
mysqltest: At line 2: Only == and != are supported for string 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 +835,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
|
||||
|
@ -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)
|
||||
{
|
||||
@ -1174,6 +1175,179 @@ while ($counter)
|
||||
let $counter=000;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Test if with compare conditions
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
let $ifvar= 5;
|
||||
let $ifvar2= 6;
|
||||
|
||||
if ($ifvar < 7)
|
||||
{
|
||||
echo 5<7;
|
||||
}
|
||||
if ($ifvar< 7)
|
||||
{
|
||||
echo 5<7 again;
|
||||
}
|
||||
if ($ifvar<7)
|
||||
{
|
||||
echo 5<7 still;
|
||||
}
|
||||
if ($ifvar < $ifvar2)
|
||||
{
|
||||
echo 5<6;
|
||||
}
|
||||
if ($ifvar <= 4)
|
||||
{
|
||||
echo 5<=4;
|
||||
}
|
||||
if ($ifvar >= 5)
|
||||
{
|
||||
echo 5>=5;
|
||||
}
|
||||
if ($ifvar>=5)
|
||||
{
|
||||
echo 5>=5 again;
|
||||
}
|
||||
if ($ifvar > 3)
|
||||
{
|
||||
echo 5>3;
|
||||
}
|
||||
if ($ifvar == 4)
|
||||
{
|
||||
echo 5==4;
|
||||
}
|
||||
if ($ifvar == 5)
|
||||
{
|
||||
echo 5==5;
|
||||
}
|
||||
if ($ifvar != 8)
|
||||
{
|
||||
echo 5!=8;
|
||||
}
|
||||
# Any number should compare unequal to any string
|
||||
if ($ifvar != five)
|
||||
{
|
||||
echo 5!=five;
|
||||
}
|
||||
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;
|
||||
}
|
||||
# Non-empty string treated as 'true'
|
||||
if (`SELECT 'something'`)
|
||||
{
|
||||
echo anything goes;
|
||||
}
|
||||
# Make sure 0 and string compare right
|
||||
let $ifvar= 0;
|
||||
if ($ifvar == string)
|
||||
{
|
||||
echo 0 == string;
|
||||
}
|
||||
if ($ifvar != string)
|
||||
{
|
||||
echo 0 != string;
|
||||
}
|
||||
--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 +2703,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
|
||||
# ----------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user