Commit 5d39c1c6 authored by unknown's avatar unknown

Improve and fix bugs in 'read_line' function of mysqltest


client/mysqltest.c:
  Fix bugs in 'read_line' function, add better comments and some DBUG printouts
  Add do_delimiter function so the "delimiter" command is parsed better, it should not be allowed to have emtpy delimiter 
  Add checks that disable/enable_pasring is not used when it's already disabled or enabled.
  Don't allow mysqltest to end with parsing disabled
  Add function 'convert_to_format_v1' as the bugs in read_line caused the queries to be read a little funny
  and we want to preserve the result file format(at this time)
mysql-test/r/mysqltest.result:
  Update result file
parent ff99e042
......@@ -1530,7 +1530,7 @@ void do_system(struct st_query *command)
SYNOPSIS
do_echo()
q called command
command called command
DESCRIPTION
echo text
......@@ -1549,14 +1549,12 @@ void do_system(struct st_query *command)
int do_echo(struct st_query *command)
{
DYNAMIC_STRING *ds, ds_echo;
ds= &ds_res;
DYNAMIC_STRING ds_echo;
init_dynamic_string(&ds_echo, "", command->query_len, 256);
do_eval(&ds_echo, command->first_argument, FALSE);
dynstr_append_mem(ds, ds_echo.str, ds_echo.length);
dynstr_append_mem(ds, "\n", 1);
dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length);
dynstr_append_mem(&ds_res, "\n", 1);
dynstr_free(&ds_echo);
command->last_argument= command->end;
return(0);
......@@ -2901,9 +2899,7 @@ void do_block(enum block_cmd cmd, struct st_query* q)
while (*p && my_isspace(charset_info, *p))
p++;
if (*p == '{')
die("Missing newline between %s and '{'", cmd_name);
if (*p)
if (*p && *p != '{')
die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
var_init(&v,0,0,0,0);
......@@ -2971,6 +2967,27 @@ my_bool end_of_query(int c)
}
void do_delimiter(struct st_query* command)
{
char* p= command->first_argument;
DBUG_ENTER("do_delimiter");
DBUG_PRINT("enter", ("first_argument: %s", command->first_argument));
while (*p && my_isspace(charset_info, *p))
p++;
if (!(*p))
die("Can't set empty delimiter");
strmake(delimiter, p, sizeof(delimiter) - 1);
delimiter_length= strlen(delimiter);
DBUG_PRINT("exit", ("delimiter: %s", delimiter));
command->last_argument= p + delimiter_length;
DBUG_VOID_RETURN;
}
/*
Read one "line" from the file
......@@ -2997,19 +3014,19 @@ my_bool end_of_query(int c)
int read_line(char *buf, int size)
{
int c;
char quote;
char c, last_quote;
char *p= buf, *buf_end= buf + size - 1;
int no_save= 0;
enum {R_NORMAL, R_Q, R_Q_IN_Q, R_SLASH_IN_Q,
R_COMMENT, R_LINE_START} state= R_LINE_START;
int skip_char= 0;
enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
R_COMMENT, R_LINE_START} state= R_LINE_START;
DBUG_ENTER("read_line");
LINT_INIT(quote);
LINT_INIT(last_quote);
start_lineno= cur_file->lineno;
DBUG_PRINT("info", ("start_lineno: %d", start_lineno));
for (; p < buf_end ;)
{
no_save= 0;
skip_char= 0;
c= my_getc(cur_file->file);
if (feof(cur_file->file))
{
......@@ -3029,8 +3046,9 @@ int read_line(char *buf, int size)
if (cur_block != block_stack)
die("Missing end of block");
*p= 0;
DBUG_PRINT("info", ("end of file"));
DBUG_RETURN(1);
DBUG_RETURN(1);
}
cur_file--;
start_lineno= cur_file->lineno;
......@@ -3044,61 +3062,74 @@ int read_line(char *buf, int size)
/* Convert cr/lf to lf */
if (p != buf && *(p-1) == '\r')
*(p-1)= 0;
p--;
}
switch(state) {
case R_NORMAL:
/* Only accept '{' in the beginning of a line */
if (end_of_query(c))
{
*p= 0;
DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter));
DBUG_RETURN(0);
}
else if (c == '\'' || c == '"' || c == '`')
else if ((c == '{' &&
(!strncasecmp(buf, "while", min(5, p - buf)) ||
!strncasecmp(buf, "if", min(2, p - buf)))))
{
quote= c;
state= R_Q;
/* Only if and while commands can be terminated by { */
*p++= c;
*p= 0;
DBUG_PRINT("exit", ("Found '{' indicating begining of block"));
DBUG_RETURN(0);
}
else if (c == '\n')
else if (c == '\'' || c == '"' || c == '`')
{
state = R_LINE_START;
last_quote= c;
state= R_Q;
}
break;
case R_COMMENT:
if (c == '\n')
{
/* Comments are terminated by newline */
*p= 0;
DBUG_PRINT("exit", ("Found newline in comment"));
DBUG_RETURN(0);
}
break;
case R_LINE_START:
/* Only accept start of comment if this is the first line in query */
if ((cur_file->lineno == start_lineno) &&
(c == '#' || c == '-' || parsing_disabled))
if (c == '#' || c == '-')
{
/* A # or - in the first position of the line - this is a comment */
state = R_COMMENT;
}
else if (my_isspace(charset_info, c))
{
/* Skip all space at begining of line */
if (c == '\n')
start_lineno= cur_file->lineno; /* Query hasn't started yet */
no_save= 1;
skip_char= 1;
}
else if (c == '}')
else if (end_of_query(c))
{
*buf++= '}';
*buf= 0;
*p= 0;
DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter));
DBUG_RETURN(0);
}
else if (end_of_query(c) || c == '{')
else if (c == '}')
{
/* A "}" need to be by itself in the begining of a line to terminate */
*p++= c;
*p= 0;
DBUG_PRINT("exit", ("Found '}' in begining of a line"));
DBUG_RETURN(0);
}
else if (c == '\'' || c == '"' || c == '`')
{
quote= c;
last_quote= c;
state= R_Q;
}
else
......@@ -3106,29 +3137,19 @@ int read_line(char *buf, int size)
break;
case R_Q:
if (c == quote)
state= R_Q_IN_Q;
if (c == last_quote)
state= R_NORMAL;
else if (c == '\\')
state= R_SLASH_IN_Q;
break;
case R_Q_IN_Q:
if (end_of_query(c))
{
*p= 0;
DBUG_RETURN(0);
}
if (c != quote)
state= R_NORMAL;
else
state= R_Q;
break;
case R_SLASH_IN_Q:
state= R_Q;
break;
}
if (!no_save)
if (!skip_char)
{
/* Could be a multibyte character */
/* This code is based on the code in "sql_load.cc" */
......@@ -3146,7 +3167,7 @@ int read_line(char *buf, int size)
for (i= 1; i < charlen; i++)
{
if (feof(cur_file->file))
goto found_eof; /* FIXME: could we just break here?! */
goto found_eof;
c= my_getc(cur_file->file);
*p++ = c;
}
......@@ -3163,10 +3184,64 @@ int read_line(char *buf, int size)
*p++= c;
}
}
*p= 0; /* Always end with \0 */
DBUG_RETURN(feof(cur_file->file));
die("The input buffer is too small for this query.x\n" \
"check your query or increase MAX_QUERY and recompile");
DBUG_RETURN(0);
}
/*
Convert the read query to format version 1
That is: After newline, all spaces need to be skipped
unless the previous char was a quote
This is due to an old bug that has now been fixed, but the
version 1 output format is preserved by using this function
*/
static void convert_to_format_v1(char* query)
{
int last_c_was_quote= 0;
char *p= query, *write= query;
char *end= strend(query);
char last_c;
while (p <= end)
{
if (*p == '\n' && !last_c_was_quote)
{
*write++ = *p++; /* Save the newline */
/* Skip any spaces on next line */
while (*p && my_isspace(charset_info, *p))
p++;
last_c_was_quote= 0;
}
else if (*p == '\'' || *p == '"' || *p == '`')
{
last_c= *p;
*write++ = *p++;
/* Copy anything until the next quote of same type */
while (*p && *p != last_c)
*write++ = *p++;
*write++ = *p++;
last_c_was_quote= 1;
}
else
{
*write++ = *p++;
last_c_was_quote= 0;
}
}
}
/*
Create a query from a set of lines
......@@ -3216,7 +3291,9 @@ int read_query(struct st_query** q_ptr)
check_eol_junk(read_query_buf);
DBUG_RETURN(1);
}
convert_to_format_v1(read_query_buf);
DBUG_PRINT("info", ("query: %s", read_query_buf));
if (*p == '#')
{
......@@ -3871,9 +3948,11 @@ static void fix_win_paths(const char* val, int len)
}
#endif
/* Append the string to ds, with optional replace */
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
const char *val, int len)
const char *val, int len)
{
#ifdef __WIN__
fix_win_paths(val, len);
......@@ -5032,7 +5111,7 @@ void get_query_type(struct st_query* q)
}
else if (q->type == Q_COMMENT_WITH_COMMAND &&
q->first_word_len &&
q->query[q->first_word_len-1] == ';')
strcmp(q->query + q->first_word_len - 1, delimiter) == 0)
{
/*
Detect comment with command using extra delimiter
......@@ -5142,7 +5221,7 @@ static void init_var_hash(MYSQL *mysql)
test run completes
*/
static void mark_progress(struct st_query* q, int line)
static void mark_progress(struct st_query* q __attribute__((unused)), int line)
{
char buf[32], *end;
ulonglong timer= timer_now();
......@@ -5332,9 +5411,7 @@ int main(int argc, char **argv)
case Q_ECHO: do_echo(q); query_executed= 1; break;
case Q_SYSTEM: do_system(q); break;
case Q_DELIMITER:
strmake(delimiter, q->first_argument, sizeof(delimiter) - 1);
delimiter_length= strlen(delimiter);
q->last_argument= q->first_argument+delimiter_length;
do_delimiter(q);
break;
case Q_DISPLAY_VERTICAL_RESULTS:
display_result_vertically= TRUE;
......@@ -5494,7 +5571,10 @@ int main(int argc, char **argv)
break;
}
case Q_DISABLE_PARSING:
parsing_disabled++;
if (parsing_disabled == 0)
parsing_disabled++;
else
die("Parsing is already disabled");
break;
case Q_ENABLE_PARSING:
/*
......@@ -5503,6 +5583,8 @@ int main(int argc, char **argv)
*/
if (parsing_disabled > 0)
parsing_disabled--;
else
die("Parsing is already enabled");
break;
case Q_EXIT:
......@@ -5545,6 +5627,9 @@ int main(int argc, char **argv)
start_lineno= 0;
if (parsing_disabled)
die("Test ended with parsing disabled");
/*
The whole test has been executed _sucessfully_.
Time to compare result or save it to record file.
......
......@@ -335,10 +335,10 @@ 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' command - end of block before beginning
mysqltest: At line 1: query '' failed: 1065: Query was empty
mysqltest: At line 1: query '{' 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 '{' at line 1
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 '{'
mysqltest: At line 3: Missing end of block
mysqltest: At line 1: missing '(' in if
mysqltest: At line 1: Stray 'end' command - end of block before beginning
select "b" bs col1, "c" bs col2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment