Below is the list of changes that have just been committed into a local
5.1 repository of malff. When malff does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2008-03-20 11:57:34-06:00, malff@stripped. +7 -0
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
Before this fix, the lexer and parser would treat the ';' character as a
different token (either ';' or END_OF_INPUT), based on convoluted logic,
which failed in simple cases where a stored procedure is implemented as a
single statement, and used in a multi query.
With this fix:
- the character ';' is always parsed as a ';' token in the lexer,
- parsing multi queries is implemented in the parser, in the 'query:' rules,
- the value of thd->client_capabilities, which is the capabilities
negotiated between the client and the server during bootstrap,
is immutable and not arbitrarily modified during parsing (which was the
root cause of the bug)
mysql-test/r/comments.result@stripped, 2008-03-20 11:57:28-06:00, malff@stripped. +1 -1
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
mysql-test/r/parser.result@stripped, 2008-03-20 11:57:28-06:00, malff@stripped. +68 -0
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
mysql-test/r/ps.result@stripped, 2008-03-20 11:57:28-06:00, malff@stripped. +2 -2
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
mysql-test/t/parser.test@stripped, 2008-03-20 11:57:28-06:00, malff@stripped. +42 -0
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
sql/sql_lex.cc@stripped, 2008-03-20 11:57:28-06:00, malff@stripped. +3 -18
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
sql/sql_parse.cc@stripped, 2008-03-20 11:57:28-06:00, malff@stripped. +6 -0
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
sql/sql_yacc.yy@stripped, 2008-03-20 11:57:29-06:00, malff@stripped. +44 -82
Bug#26030 (Parsing fails for stored routine w/multi-statement execution
enabled)
diff -Nrup a/mysql-test/r/comments.result b/mysql-test/r/comments.result
--- a/mysql-test/r/comments.result 2007-08-30 12:57:00 -06:00
+++ b/mysql-test/r/comments.result 2008-03-20 11:57:28 -06:00
@@ -45,7 +45,7 @@ ERROR 42000: You have an error in your S
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;";
ERROR 42000: 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
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*! AND 2=2;*";
-ERROR 42000: 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
+ERROR 42000: 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
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';";
ERROR 42000: 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 '/*!98765' AND b = 'bar'' at line 1
prepare bar from "DELETE FROM table_28779 WHERE a = 7 OR 1=1/*!98765' AND b = 'bar';*";
diff -Nrup a/mysql-test/r/parser.result b/mysql-test/r/parser.result
--- a/mysql-test/r/parser.result 2007-12-19 15:59:56 -07:00
+++ b/mysql-test/r/parser.result 2008-03-20 11:57:28 -06:00
@@ -284,6 +284,74 @@ Field Type Null Key Default Extra
DROP TABLE table_25930_a;
DROP TABLE table_25930_b;
SET @@sql_mode=@save_sql_mode;
+DROP PROCEDURE IF EXISTS p26030;
+select "non terminated"$$
+non terminated
+non terminated
+select "terminated";$$
+terminated
+terminated
+select "non terminated, space" $$
+non terminated, space
+non terminated, space
+select "terminated, space"; $$
+terminated, space
+terminated, space
+select "non terminated, comment" /* comment */$$
+non terminated, comment
+non terminated, comment
+select "terminated, comment"; /* comment */$$
+terminated, comment
+terminated, comment
+select "stmt 1";select "stmt 2 non terminated"$$
+stmt 1
+stmt 1
+stmt 2 non terminated
+stmt 2 non terminated
+select "stmt 1";select "stmt 2 terminated";$$
+stmt 1
+stmt 1
+stmt 2 terminated
+stmt 2 terminated
+select "stmt 1";select "stmt 2 non terminated, space" $$
+stmt 1
+stmt 1
+stmt 2 non terminated, space
+stmt 2 non terminated, space
+select "stmt 1";select "stmt 2 terminated, space"; $$
+stmt 1
+stmt 1
+stmt 2 terminated, space
+stmt 2 terminated, space
+select "stmt 1";select "stmt 2 non terminated, comment" /* comment */$$
+stmt 1
+stmt 1
+stmt 2 non terminated, comment
+stmt 2 non terminated, comment
+select "stmt 1";select "stmt 2 terminated, comment"; /* comment */$$
+stmt 1
+stmt 1
+stmt 2 terminated, comment
+stmt 2 terminated, comment
+select "stmt 1"; select "space, stmt 2"$$
+stmt 1
+stmt 1
+space, stmt 2
+space, stmt 2
+select "stmt 1";/* comment */select "comment, stmt 2"$$
+stmt 1
+stmt 1
+comment, stmt 2
+comment, stmt 2
+DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() BEGIN SELECT 1; END; CALL p26030()
+$$
+1
+1
+DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() SELECT 1; CALL p26030()
+$$
+1
+1
+DROP PROCEDURE p26030;
select pi(3.14);
ERROR 42000: Incorrect parameter count in the call to native function 'pi'
select tan();
diff -Nrup a/mysql-test/r/ps.result b/mysql-test/r/ps.result
--- a/mysql-test/r/ps.result 2008-02-28 16:19:35 -07:00
+++ b/mysql-test/r/ps.result 2008-03-20 11:57:28 -06:00
@@ -85,9 +85,9 @@ NULL
NULL
NULL
prepare stmt6 from 'select 1; select2';
-ERROR 42000: 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 '; select2' at line 1
+ERROR 42000: 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 'select2' at line 1
prepare stmt6 from 'insert into t1 values (5,"five"); select2';
-ERROR 42000: 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 '; select2' at line 1
+ERROR 42000: 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 'select2' at line 1
explain prepare stmt6 from 'insert into t1 values (5,"five"); select2';
ERROR 42000: 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 'from 'insert into t1 values (5,"five"); select2'' at line 1
create table t2
diff -Nrup a/mysql-test/t/parser.test b/mysql-test/t/parser.test
--- a/mysql-test/t/parser.test 2007-12-19 15:59:56 -07:00
+++ b/mysql-test/t/parser.test 2008-03-20 11:57:28 -06:00
@@ -6,6 +6,11 @@
# LEXICAL PARSER (lex)
#=============================================================================
+#
+# Maintainer: these tests are for the lexical parser, so every character,
+# even whitespace or comments, is significant here.
+#
+
SET @save_sql_mode=@@sql_mode;
#
@@ -386,6 +391,43 @@ DROP TABLE table_25930_b;
SET @@sql_mode=@save_sql_mode;
+
+#
+# Bug#26030 (Parsing fails for stored routine w/multi-statement execution
+# enabled)
+#
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS p26030;
+--enable_warnings
+
+delimiter $$;
+
+select "non terminated"$$
+select "terminated";$$
+select "non terminated, space" $$
+select "terminated, space"; $$
+select "non terminated, comment" /* comment */$$
+select "terminated, comment"; /* comment */$$
+
+select "stmt 1";select "stmt 2 non terminated"$$
+select "stmt 1";select "stmt 2 terminated";$$
+select "stmt 1";select "stmt 2 non terminated, space" $$
+select "stmt 1";select "stmt 2 terminated, space"; $$
+select "stmt 1";select "stmt 2 non terminated, comment" /* comment */$$
+select "stmt 1";select "stmt 2 terminated, comment"; /* comment */$$
+
+select "stmt 1"; select "space, stmt 2"$$
+select "stmt 1";/* comment */select "comment, stmt 2"$$
+
+DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() BEGIN SELECT 1; END; CALL p26030()
+$$
+
+DROP PROCEDURE IF EXISTS p26030; CREATE PROCEDURE p26030() SELECT 1; CALL p26030()
+$$
+
+delimiter ;$$
+DROP PROCEDURE p26030;
#=============================================================================
# SYNTACTIC PARSER (bison)
diff -Nrup a/sql/sql_lex.cc b/sql/sql_lex.cc
--- a/sql/sql_lex.cc 2008-02-22 03:30:30 -07:00
+++ b/sql/sql_lex.cc 2008-03-20 11:57:28 -06:00
@@ -1317,23 +1317,8 @@ int MYSQLlex(void *arg, void *yythd)
lip->yySkip();
return (SET_VAR);
case MY_LEX_SEMICOLON: // optional line terminator
- if (lip->yyPeek())
- {
- if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) &&
- !lip->stmt_prepare_mode)
- {
- lex->safe_to_cache_query= 0;
- lip->found_semicolon= lip->get_ptr();
- thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
- lip->next_state= MY_LEX_END;
- lip->set_echo(TRUE);
- return (END_OF_INPUT);
- }
- state= MY_LEX_CHAR; // Return ';'
- break;
- }
- lip->next_state=MY_LEX_END; // Mark for next loop
- return(END_OF_INPUT);
+ state= MY_LEX_CHAR; // Return ';'
+ break;
case MY_LEX_EOL:
if (lip->eof())
{
@@ -1352,7 +1337,7 @@ int MYSQLlex(void *arg, void *yythd)
case MY_LEX_END:
lip->next_state=MY_LEX_END;
return(0); // We found end of input last time
-
+
/* Actually real shouldn't start with . but allow them anyhow */
case MY_LEX_REAL_OR_POINT:
if (my_isdigit(cs,lip->yyPeek()))
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc 2008-03-12 02:21:10 -06:00
+++ b/sql/sql_parse.cc 2008-03-20 11:57:28 -06:00
@@ -5656,6 +5656,11 @@ void mysql_parse(THD *thd, const char *i
(thd->query_length= (ulong)(*found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
+ if (*found_semicolon)
+ {
+ lex->safe_to_cache_query= 0;
+ thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
+ }
lex->set_trg_event_type_for_tables();
mysql_execute_command(thd);
}
@@ -7448,6 +7453,7 @@ bool parse_sql(THD *thd,
/* Set Lex_input_stream. */
+ lip->set_echo(TRUE);
thd->m_lip= lip;
/* Parse the query. */
diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy 2008-03-12 02:21:10 -06:00
+++ b/sql/sql_yacc.yy 2008-03-20 11:57:29 -06:00
@@ -1349,12 +1349,44 @@ query:
my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
MYSQL_YYABORT;
}
+ thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
+ thd->m_lip->found_semicolon= NULL;
+ }
+ | verb_clause
+ {
+ Lex_input_stream *lip = YYTHD->m_lip;
+
+ if ((YYTHD->client_capabilities & CLIENT_MULTI_QUERIES) &&
+ ! lip->stmt_prepare_mode &&
+ ! lip->eof())
+ {
+ /*
+ We found a well formed query, and multi queries are allowed:
+ - force the parser to stop after the ';'
+ - mark the start of the next query for the next invocation
+ of the parser.
+ */
+ lip->next_state= MY_LEX_END;
+ lip->found_semicolon= lip->get_ptr();
+ }
else
{
- thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
+ /* Single query, terminated. */
+ lip->found_semicolon= NULL;
}
}
- | verb_clause END_OF_INPUT {}
+ ';'
+ opt_end_of_input
+ | verb_clause END_OF_INPUT
+ {
+ /* Single query, not terminated. */
+ YYTHD->m_lip->found_semicolon= NULL;
+ }
+ ;
+
+opt_end_of_input:
+ /* empty */
+ | END_OF_INPUT
;
verb_clause:
@@ -1768,10 +1800,6 @@ server_option:
event_tail:
EVENT_SYM opt_if_not_exists sp_name
- /*
- BE CAREFUL when you add a new rule to update the block where
- YYTHD->client_capabilities is set back to original value
- */
{
THD *thd= YYTHD;
LEX *lex=Lex;
@@ -1782,14 +1810,6 @@ event_tail:
MYSQL_YYABORT;
lex->event_parse_data->identifier= $3;
- /*
- We have to turn of CLIENT_MULTI_QUERIES while parsing a
- stored procedure, otherwise yylex will chop it into pieces
- at each ';'.
- */
- $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
- thd->client_capabilities &= (~CLIENT_MULTI_QUERIES);
-
lex->sql_command= SQLCOM_CREATE_EVENT;
/* We need that for disallowing subqueries */
}
@@ -1800,15 +1820,6 @@ event_tail:
DO_SYM ev_sql_stmt
{
/*
- Restore flag if it was cleared above
- $1 - EVENT_SYM
- $2 - opt_if_not_exists
- $3 - sp_name
- $4 - the block above
- */
- YYTHD->client_capabilities |= $<ulong_num>4;
-
- /*
sql_command is set here because some rules in ev_sql_stmt
can overwrite it
*/
@@ -5383,12 +5394,11 @@ alter:
}
view_tail
{}
- | ALTER definer_opt EVENT_SYM sp_name
- /*
- BE CAREFUL when you add a new rule to update the block where
- YYTHD->client_capabilities is set back to original value
- */
- {
+ | ALTER /* $1 */
+ definer_opt /* $2 */
+ EVENT_SYM /* $3 */
+ sp_name /* $4 */
+ { /* $5 */
/*
It is safe to use Lex->spname because
ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
@@ -5401,31 +5411,14 @@ alter:
MYSQL_YYABORT;
Lex->event_parse_data->identifier= $4;
- /*
- We have to turn off CLIENT_MULTI_QUERIES while parsing a
- stored procedure, otherwise yylex will chop it into pieces
- at each ';'.
- */
- $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
- YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
-
Lex->sql_command= SQLCOM_ALTER_EVENT;
}
- ev_alter_on_schedule_completion
- opt_ev_rename_to
- opt_ev_status
- opt_ev_comment
- opt_ev_sql_stmt
+ ev_alter_on_schedule_completion /* $6 */
+ opt_ev_rename_to /* $7 */
+ opt_ev_status /* $8 */
+ opt_ev_comment /* $9 */
+ opt_ev_sql_stmt /* $10 */
{
- /*
- $1 - ALTER
- $2 - definer_opt
- $3 - EVENT_SYM
- $4 - sp_name
- $5 - the block above
- */
- YYTHD->client_capabilities |= $<ulong_num>5;
-
if (!($6 || $7 || $8 || $9 || $10))
{
my_parse_error(ER(ER_SYNTAX_ERROR));
@@ -12142,13 +12135,6 @@ trigger_tail:
lex->sphead= sp;
lex->spname= $3;
- /*
- We have to turn of CLIENT_MULTI_QUERIES while parsing a
- stored procedure, otherwise yylex will chop it into pieces
- at each ';'.
- */
- $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
- thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
@@ -12161,9 +12147,7 @@ trigger_tail:
lex->sql_command= SQLCOM_CREATE_TRIGGER;
sp->set_stmt_end(YYTHD);
- /* Restore flag if it was cleared above */
- YYTHD->client_capabilities |= $<ulong_num>15;
sp->restore_thd_mem_root(YYTHD);
if (sp->is_not_allowed_in_function("trigger"))
@@ -12255,13 +12239,6 @@ sf_tail:
sp->m_type= TYPE_ENUM_FUNCTION;
lex->sphead= sp;
- /*
- We have to turn off CLIENT_MULTI_QUERIES while parsing a
- stored procedure, otherwise yylex will chop it into pieces
- at each ';'.
- */
- $<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
- thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
tmp_param_begin= lip->get_cpp_tok_start();
tmp_param_begin++;
@@ -12367,8 +12344,6 @@ sf_tail:
ER(ER_NATIVE_FCT_NAME_COLLISION),
sp->m_name.str);
}
- /* Restore flag if it was cleared above */
- thd->client_capabilities |= $<ulong_num>5;
sp->restore_thd_mem_root(thd);
}
;
@@ -12395,13 +12370,6 @@ sp_tail:
sp->init_sp_name(YYTHD, $3);
lex->sphead= sp;
- /*
- * We have to turn of CLIENT_MULTI_QUERIES while parsing a
- * stored procedure, otherwise yylex will chop it into pieces
- * at each ';'.
- */
- $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
- YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
}
'('
{
@@ -12440,12 +12408,6 @@ sp_tail:
sp->set_stmt_end(YYTHD);
lex->sql_command= SQLCOM_CREATE_PROCEDURE;
- /*
- Restore flag if it was cleared above
- Be careful with counting. the block where we save the value
- is $4.
- */
- YYTHD->client_capabilities |= $<ulong_num>4;
sp->restore_thd_mem_root(YYTHD);
}
;
| Thread |
|---|
| • bk commit into 5.1 tree (malff:1.2563) BUG#26030 | marc.alff | 20 Mar |