Improve and fix bugs in 'read_line' function of mysqltest

parent 1dd4ecaa
...@@ -1530,7 +1530,7 @@ void do_system(struct st_query *command) ...@@ -1530,7 +1530,7 @@ void do_system(struct st_query *command)
SYNOPSIS SYNOPSIS
do_echo() do_echo()
q called command command called command
DESCRIPTION DESCRIPTION
echo text echo text
...@@ -1549,14 +1549,12 @@ void do_system(struct st_query *command) ...@@ -1549,14 +1549,12 @@ void do_system(struct st_query *command)
int do_echo(struct st_query *command) int do_echo(struct st_query *command)
{ {
DYNAMIC_STRING *ds, ds_echo; DYNAMIC_STRING ds_echo;
ds= &ds_res;
init_dynamic_string(&ds_echo, "", command->query_len, 256); init_dynamic_string(&ds_echo, "", command->query_len, 256);
do_eval(&ds_echo, command->first_argument, FALSE); do_eval(&ds_echo, command->first_argument, FALSE);
dynstr_append_mem(ds, ds_echo.str, ds_echo.length); dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length);
dynstr_append_mem(ds, "\n", 1); dynstr_append_mem(&ds_res, "\n", 1);
dynstr_free(&ds_echo); dynstr_free(&ds_echo);
command->last_argument= command->end; command->last_argument= command->end;
return(0); return(0);
...@@ -2901,9 +2899,7 @@ void do_block(enum block_cmd cmd, struct st_query* q) ...@@ -2901,9 +2899,7 @@ void do_block(enum block_cmd cmd, struct st_query* q)
while (*p && my_isspace(charset_info, *p)) while (*p && my_isspace(charset_info, *p))
p++; p++;
if (*p == '{') if (*p && *p != '{')
die("Missing newline between %s and '{'", cmd_name);
if (*p)
die("Missing '{' after %s. Found \"%s\"", cmd_name, p); die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
var_init(&v,0,0,0,0); var_init(&v,0,0,0,0);
...@@ -2971,6 +2967,27 @@ my_bool end_of_query(int c) ...@@ -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 Read one "line" from the file
...@@ -2997,19 +3014,19 @@ my_bool end_of_query(int c) ...@@ -2997,19 +3014,19 @@ my_bool end_of_query(int c)
int read_line(char *buf, int size) int read_line(char *buf, int size)
{ {
int c; char c, last_quote;
char quote;
char *p= buf, *buf_end= buf + size - 1; char *p= buf, *buf_end= buf + size - 1;
int no_save= 0; int skip_char= 0;
enum {R_NORMAL, R_Q, R_Q_IN_Q, R_SLASH_IN_Q, enum {R_NORMAL, R_Q, R_SLASH_IN_Q,
R_COMMENT, R_LINE_START} state= R_LINE_START; R_COMMENT, R_LINE_START} state= R_LINE_START;
DBUG_ENTER("read_line"); DBUG_ENTER("read_line");
LINT_INIT(quote); LINT_INIT(last_quote);
start_lineno= cur_file->lineno; start_lineno= cur_file->lineno;
DBUG_PRINT("info", ("start_lineno: %d", start_lineno));
for (; p < buf_end ;) for (; p < buf_end ;)
{ {
no_save= 0; skip_char= 0;
c= my_getc(cur_file->file); c= my_getc(cur_file->file);
if (feof(cur_file->file)) if (feof(cur_file->file))
{ {
...@@ -3029,8 +3046,9 @@ int read_line(char *buf, int size) ...@@ -3029,8 +3046,9 @@ int read_line(char *buf, int size)
if (cur_block != block_stack) if (cur_block != block_stack)
die("Missing end of block"); die("Missing end of block");
*p= 0;
DBUG_PRINT("info", ("end of file")); DBUG_PRINT("info", ("end of file"));
DBUG_RETURN(1); DBUG_RETURN(1);
} }
cur_file--; cur_file--;
start_lineno= cur_file->lineno; start_lineno= cur_file->lineno;
...@@ -3044,61 +3062,74 @@ int read_line(char *buf, int size) ...@@ -3044,61 +3062,74 @@ int read_line(char *buf, int size)
/* Convert cr/lf to lf */ /* Convert cr/lf to lf */
if (p != buf && *(p-1) == '\r') if (p != buf && *(p-1) == '\r')
*(p-1)= 0; p--;
} }
switch(state) { switch(state) {
case R_NORMAL: case R_NORMAL:
/* Only accept '{' in the beginning of a line */
if (end_of_query(c)) if (end_of_query(c))
{ {
*p= 0; *p= 0;
DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter));
DBUG_RETURN(0); 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; /* Only if and while commands can be terminated by { */
state= R_Q; *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; break;
case R_COMMENT: case R_COMMENT:
if (c == '\n') if (c == '\n')
{ {
/* Comments are terminated by newline */
*p= 0; *p= 0;
DBUG_PRINT("exit", ("Found newline in comment"));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
break; break;
case R_LINE_START: case R_LINE_START:
/* Only accept start of comment if this is the first line in query */ if (c == '#' || c == '-')
if ((cur_file->lineno == start_lineno) &&
(c == '#' || c == '-' || parsing_disabled))
{ {
/* A # or - in the first position of the line - this is a comment */
state = R_COMMENT; state = R_COMMENT;
} }
else if (my_isspace(charset_info, c)) else if (my_isspace(charset_info, c))
{ {
/* Skip all space at begining of line */
if (c == '\n') if (c == '\n')
start_lineno= cur_file->lineno; /* Query hasn't started yet */ 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++= '}'; *p= 0;
*buf= 0; DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter));
DBUG_RETURN(0); 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; *p= 0;
DBUG_PRINT("exit", ("Found '}' in begining of a line"));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
else if (c == '\'' || c == '"' || c == '`') else if (c == '\'' || c == '"' || c == '`')
{ {
quote= c; last_quote= c;
state= R_Q; state= R_Q;
} }
else else
...@@ -3106,29 +3137,19 @@ int read_line(char *buf, int size) ...@@ -3106,29 +3137,19 @@ int read_line(char *buf, int size)
break; break;
case R_Q: case R_Q:
if (c == quote) if (c == last_quote)
state= R_Q_IN_Q; state= R_NORMAL;
else if (c == '\\') else if (c == '\\')
state= R_SLASH_IN_Q; state= R_SLASH_IN_Q;
break; 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: case R_SLASH_IN_Q:
state= R_Q; state= R_Q;
break; break;
} }
if (!no_save) if (!skip_char)
{ {
/* Could be a multibyte character */ /* Could be a multibyte character */
/* This code is based on the code in "sql_load.cc" */ /* This code is based on the code in "sql_load.cc" */
...@@ -3146,7 +3167,7 @@ int read_line(char *buf, int size) ...@@ -3146,7 +3167,7 @@ int read_line(char *buf, int size)
for (i= 1; i < charlen; i++) for (i= 1; i < charlen; i++)
{ {
if (feof(cur_file->file)) if (feof(cur_file->file))
goto found_eof; /* FIXME: could we just break here?! */ goto found_eof;
c= my_getc(cur_file->file); c= my_getc(cur_file->file);
*p++ = c; *p++ = c;
} }
...@@ -3163,10 +3184,64 @@ int read_line(char *buf, int size) ...@@ -3163,10 +3184,64 @@ int read_line(char *buf, int size)
*p++= c; *p++= c;
} }
} }
*p= 0; /* Always end with \0 */ die("The input buffer is too small for this query.x\n" \
DBUG_RETURN(feof(cur_file->file)); "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 Create a query from a set of lines
...@@ -3216,7 +3291,9 @@ int read_query(struct st_query** q_ptr) ...@@ -3216,7 +3291,9 @@ int read_query(struct st_query** q_ptr)
check_eol_junk(read_query_buf); check_eol_junk(read_query_buf);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
convert_to_format_v1(read_query_buf);
DBUG_PRINT("info", ("query: %s", read_query_buf)); DBUG_PRINT("info", ("query: %s", read_query_buf));
if (*p == '#') if (*p == '#')
{ {
...@@ -3871,9 +3948,11 @@ static void fix_win_paths(const char* val, int len) ...@@ -3871,9 +3948,11 @@ static void fix_win_paths(const char* val, int len)
} }
#endif #endif
/* Append the string to ds, with optional replace */ /* Append the string to ds, with optional replace */
static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, static void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
const char *val, int len) const char *val, int len)
{ {
#ifdef __WIN__ #ifdef __WIN__
fix_win_paths(val, len); fix_win_paths(val, len);
...@@ -5032,7 +5111,7 @@ void get_query_type(struct st_query* q) ...@@ -5032,7 +5111,7 @@ void get_query_type(struct st_query* q)
} }
else if (q->type == Q_COMMENT_WITH_COMMAND && else if (q->type == Q_COMMENT_WITH_COMMAND &&
q->first_word_len && 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 Detect comment with command using extra delimiter
...@@ -5142,7 +5221,7 @@ static void init_var_hash(MYSQL *mysql) ...@@ -5142,7 +5221,7 @@ static void init_var_hash(MYSQL *mysql)
test run completes 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; char buf[32], *end;
ulonglong timer= timer_now(); ulonglong timer= timer_now();
...@@ -5332,9 +5411,7 @@ int main(int argc, char **argv) ...@@ -5332,9 +5411,7 @@ int main(int argc, char **argv)
case Q_ECHO: do_echo(q); query_executed= 1; break; case Q_ECHO: do_echo(q); query_executed= 1; break;
case Q_SYSTEM: do_system(q); break; case Q_SYSTEM: do_system(q); break;
case Q_DELIMITER: case Q_DELIMITER:
strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); do_delimiter(q);
delimiter_length= strlen(delimiter);
q->last_argument= q->first_argument+delimiter_length;
break; break;
case Q_DISPLAY_VERTICAL_RESULTS: case Q_DISPLAY_VERTICAL_RESULTS:
display_result_vertically= TRUE; display_result_vertically= TRUE;
...@@ -5494,7 +5571,10 @@ int main(int argc, char **argv) ...@@ -5494,7 +5571,10 @@ int main(int argc, char **argv)
break; break;
} }
case Q_DISABLE_PARSING: case Q_DISABLE_PARSING:
parsing_disabled++; if (parsing_disabled == 0)
parsing_disabled++;
else
die("Parsing is already disabled");
break; break;
case Q_ENABLE_PARSING: case Q_ENABLE_PARSING:
/* /*
...@@ -5503,6 +5583,8 @@ int main(int argc, char **argv) ...@@ -5503,6 +5583,8 @@ int main(int argc, char **argv)
*/ */
if (parsing_disabled > 0) if (parsing_disabled > 0)
parsing_disabled--; parsing_disabled--;
else
die("Parsing is already enabled");
break; break;
case Q_EXIT: case Q_EXIT:
...@@ -5545,6 +5627,9 @@ int main(int argc, char **argv) ...@@ -5545,6 +5627,9 @@ int main(int argc, char **argv)
start_lineno= 0; start_lineno= 0;
if (parsing_disabled)
die("Test ended with parsing disabled");
/* /*
The whole test has been executed _sucessfully_. The whole test has been executed _sucessfully_.
Time to compare result or save it to record file. Time to compare result or save it to record file.
......
...@@ -335,10 +335,10 @@ mysqltest: At line 1: missing ')' in while ...@@ -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: 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: Stray 'end' command - 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 1: Missing '{' after while. Found "echo hej"
mysqltest: At line 3: Missing end of block 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: missing '(' in if
mysqltest: At line 1: Stray 'end' command - end of block before beginning mysqltest: At line 1: Stray 'end' command - end of block before beginning
select "b" bs col1, "c" bs col2; 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