diff options
author | Marc Alff <marc.alff@sun.com> | 2008-07-07 10:00:08 -0600 |
---|---|---|
committer | Marc Alff <marc.alff@sun.com> | 2008-07-07 10:00:08 -0600 |
commit | c7724872d85cebf07df3380757cf7259f9116682 (patch) | |
tree | 373c5fa1c21bed1d12376b834674b7bb3f0463aa /sql | |
parent | 5647bce3668b46c5c74349520cefb2a791125e95 (diff) | |
download | mariadb-git-c7724872d85cebf07df3380757cf7259f9116682.tar.gz |
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)
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sp_head.h | 1 | ||||
-rw-r--r-- | sql/sql_lex.cc | 19 | ||||
-rw-r--r-- | sql/sql_parse.cc | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 93 |
4 files changed, 56 insertions, 62 deletions
diff --git a/sql/sp_head.h b/sql/sp_head.h index 11ff7160c03..91f465a4e2a 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -117,7 +117,6 @@ public: 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 diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6bfcd982b04..a1bfc3edc6c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1010,21 +1010,8 @@ int MYSQLlex(void *arg, void *yythd) 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 @@ 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,yyPeek())) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 98e04e45bdd..62a5a79a833 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6169,6 +6169,11 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, (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); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ffc84bde9c1..090585392a0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1203,21 +1203,54 @@ END_OF_INPUT 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 @@ 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 ';'. - */ - 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 @@ trigger_tail: 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 @@ sf_tail: 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 @@ sf_tail: 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_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 ';'. - */ - sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; - YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES); } '(' { @@ -10104,9 +10110,6 @@ sp_tail: 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); } ; |