=== modified file 'mysql-test/r/comments.result'
--- a/mysql-test/r/comments.result	2007-08-29 20:50:32 +0000
+++ b/mysql-test/r/comments.result	2008-07-07 16:00:08 +0000
@@ -35,7 +35,7 @@
 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';*";

=== added file 'mysql-test/r/parser.result'
--- a/mysql-test/r/parser.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/parser.result	2008-07-07 16:00:08 +0000
@@ -0,0 +1,68 @@
+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;

=== modified file 'mysql-test/r/ps.result'
--- a/mysql-test/r/ps.result	2008-02-28 14:34:08 +0000
+++ b/mysql-test/r/ps.result	2008-07-07 16:00:08 +0000
@@ -85,9 +85,9 @@
 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

=== added file 'mysql-test/t/parser.test'
--- a/mysql-test/t/parser.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/parser.test	2008-07-07 16:00:08 +0000
@@ -0,0 +1,59 @@
+#
+# This file contains tests covering the parser
+#
+
+#=============================================================================
+# LEXICAL PARSER (lex)
+#=============================================================================
+
+#
+# Maintainer: these tests are for the lexical parser, so every character,
+# even whitespace or comments, is significant here.
+#
+
+#
+# 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 */$$
+
+# Multi queries can not be used in --ps-protocol test mode
+--disable_ps_protocol
+
+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()
+$$
+
+--enable_ps_protocol
+
+delimiter ;$$
+DROP PROCEDURE p26030;
+
+#============================================================================r
+# SYNTACTIC PARSER (bison)
+#=============================================================================
+

=== modified file 'sql/sp_head.h'
--- a/sql/sp_head.h	2008-05-15 23:13:24 +0000
+++ b/sql/sp_head.h	2008-07-07 16:00:08 +0000
@@ -117,7 +117,6 @@
   create_field m_return_field_def; /* This is used for FUNCTIONs only. */
 
   const char *m_tmp_query;	// Temporary pointer to sub query string
-  uint m_old_cmq;		// Old CLIENT_MULTI_QUERIES value
   st_sp_chistics *m_chistics;
   ulong m_sql_mode;		// For SHOW CREATE and execution
   LEX_STRING m_qname;		// db.name

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2008-03-27 16:49:32 +0000
+++ b/sql/sql_lex.cc	2008-07-07 16:00:08 +0000
@@ -1010,21 +1010,8 @@
       yySkip();
       return (SET_VAR);
     case MY_LEX_SEMICOLON:			// optional line terminator
-      if (yyPeek())
-      {
-        if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && 
-            !lip->stmt_prepare_mode)
-        {
-	  lex->safe_to_cache_query= 0;
-          lip->found_semicolon= lip->ptr;
-          thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
-          lip->next_state=     MY_LEX_END;
-          return (END_OF_INPUT);
-        }
-        state= MY_LEX_CHAR;		// Return ';'
-	break;
-      }
-      /* fall true */
+      state= MY_LEX_CHAR;               // Return ';'
+      break;
     case MY_LEX_EOL:
       if (lip->ptr >= lip->end_of_query)
       {
@@ -1039,7 +1026,7 @@
     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,yyPeek()))

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-03-21 15:23:17 +0000
+++ b/sql/sql_parse.cc	2008-07-07 16:00:08 +0000
@@ -6169,6 +6169,11 @@
               (thd->query_length= (ulong)(lip.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);
           query_cache_end_of_result(thd);

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-04-10 00:34:38 +0000
+++ b/sql/sql_yacc.yy	2008-07-07 16:00:08 +0000
@@ -1203,21 +1203,54 @@
 
 
 query:
-	END_OF_INPUT
-	{
-	   THD *thd= YYTHD;
-	   if (!thd->bootstrap &&
-	      (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
-	   {
-	     my_message(ER_EMPTY_QUERY, ER(ER_EMPTY_QUERY), MYF(0));
-	     MYSQL_YYABORT;
-	   }
-	   else
-	   {
-	     thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
-	   }
-	}
-	| verb_clause END_OF_INPUT {};
+          END_OF_INPUT
+          {
+            THD *thd= YYTHD;
+            if (!thd->bootstrap &&
+              (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
+            {
+              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->ptr >= lip->end_of_query))
+            {
+              /*
+                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->ptr;
+            }
+            else
+            {
+              /* Single query, terminated. */
+              lip->found_semicolon= NULL;
+            }
+          }
+          ';'
+          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:
 	  statement
@@ -9867,13 +9900,6 @@
 
 	  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 ';'.
-	  */
-	  sp->m_old_cmq= 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;
@@ -9888,9 +9914,6 @@
 	  
 	  lex->sql_command= SQLCOM_CREATE_TRIGGER;
 	  sp->init_strings(YYTHD, lex);
-	  /* Restore flag if it was cleared above */
-	  if (sp->m_old_cmq)
-	    YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
 	  sp->restore_thd_mem_root(YYTHD);
 	
 	  if (sp->is_not_allowed_in_function("trigger"))
@@ -9968,13 +9991,6 @@
 
 	    sp->m_type= TYPE_ENUM_FUNCTION;
 	    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 ';'.
-	     */
-	    sp->m_old_cmq= thd->client_capabilities & CLIENT_MULTI_QUERIES;
-	    thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
 	    lex->sphead->m_param_begin= lip->tok_start+1;
 	  }
           sp_fdparam_list /* $6 */
@@ -10030,9 +10046,6 @@
               my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
               MYSQL_YYABORT;
             }
-	    /* Restore flag if it was cleared above */
-	    if (sp->m_old_cmq)
-	      YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
 	    sp->restore_thd_mem_root(YYTHD);
 	  }
 	;
@@ -10062,13 +10075,6 @@
           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 ';'.
-	   */
-	  sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
-	  YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
 	}
         '('
 	{
@@ -10104,9 +10110,6 @@
 
 	  sp->init_strings(YYTHD, lex);
 	  lex->sql_command= SQLCOM_CREATE_PROCEDURE;
-	  /* Restore flag if it was cleared above */
-	  if (sp->m_old_cmq)
-	    YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
 	  sp->restore_thd_mem_root(YYTHD);
 	}
 	;



