summaryrefslogtreecommitdiff
path: root/sql/sql_parse.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r--sql/sql_parse.cc115
1 files changed, 86 insertions, 29 deletions
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index b8f2228d6e7..b1c9afa3842 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1887,6 +1887,10 @@ mysql_execute_command(THD *thd)
TABLE_LIST *all_tables;
/* most outer SELECT_LEX_UNIT of query */
SELECT_LEX_UNIT *unit= &lex->unit;
+#ifdef HAVE_REPLICATION
+ /* have table map for update for multi-update statement (BUG#37051) */
+ bool have_table_map_for_update= FALSE;
+#endif
/* Saved variable value */
DBUG_ENTER("mysql_execute_command");
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -1952,6 +1956,48 @@ mysql_execute_command(THD *thd)
// force searching in slave.cc:tables_ok()
all_tables->updating= 1;
}
+
+ /*
+ For fix of BUG#37051, the master stores the table map for update
+ in the Query_log_event, and the value is assigned to
+ thd->variables.table_map_for_update before executing the update
+ query.
+
+ If thd->variables.table_map_for_update is set, then we are
+ replicating from a new master, we can use this value to apply
+ filter rules without opening all the tables. However If
+ thd->variables.table_map_for_update is not set, then we are
+ replicating from an old master, so we just skip this and
+ continue with the old method. And of course, the bug would still
+ exist for old masters.
+ */
+ if (lex->sql_command == SQLCOM_UPDATE_MULTI &&
+ thd->table_map_for_update)
+ {
+ have_table_map_for_update= TRUE;
+ table_map table_map_for_update= thd->table_map_for_update;
+ uint nr= 0;
+ TABLE_LIST *table;
+ for (table=all_tables; table; table=table->next_global, nr++)
+ {
+ if (table_map_for_update & ((table_map)1 << nr))
+ table->updating= TRUE;
+ else
+ table->updating= FALSE;
+ }
+
+ if (all_tables_not_ok(thd, all_tables))
+ {
+ /* we warn the slave SQL thread */
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ if (thd->one_shot_set)
+ reset_one_shot_variables(thd);
+ DBUG_RETURN(0);
+ }
+
+ for (table=all_tables; table; table=table->next_global)
+ table->updating= TRUE;
+ }
/*
Check if statment should be skipped because of slave filtering
@@ -2866,7 +2912,7 @@ end_with_restore_list:
#ifdef HAVE_REPLICATION
/* Check slave filtering rules */
- if (unlikely(thd->slave_thread))
+ if (unlikely(thd->slave_thread && !have_table_map_for_update))
{
if (all_tables_not_ok(thd, all_tables))
{
@@ -5323,29 +5369,35 @@ bool check_stack_overrun(THD *thd, long margin,
bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize)
{
- LEX *lex= current_thd->lex;
+ Yacc_state *state= & current_thd->m_parser_state->m_yacc;
ulong old_info=0;
+ DBUG_ASSERT(state);
if ((uint) *yystacksize >= MY_YACC_MAX)
return 1;
- if (!lex->yacc_yyvs)
+ if (!state->yacc_yyvs)
old_info= *yystacksize;
*yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX);
- if (!(lex->yacc_yyvs= (uchar*)
- my_realloc(lex->yacc_yyvs,
- *yystacksize*sizeof(**yyvs),
- MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
- !(lex->yacc_yyss= (uchar*)
- my_realloc(lex->yacc_yyss,
- *yystacksize*sizeof(**yyss),
- MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
+ if (!(state->yacc_yyvs= (uchar*)
+ my_realloc(state->yacc_yyvs,
+ *yystacksize*sizeof(**yyvs),
+ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
+ !(state->yacc_yyss= (uchar*)
+ my_realloc(state->yacc_yyss,
+ *yystacksize*sizeof(**yyss),
+ MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
return 1;
if (old_info)
- { // Copy old info from stack
- memcpy(lex->yacc_yyss, (uchar*) *yyss, old_info*sizeof(**yyss));
- memcpy(lex->yacc_yyvs, (uchar*) *yyvs, old_info*sizeof(**yyvs));
+ {
+ /*
+ Only copy the old stack on the first call to my_yyoverflow(),
+ when replacing a static stack (YYINITDEPTH) by a dynamic stack.
+ For subsequent calls, my_realloc already did preserve the old stack.
+ */
+ memcpy(state->yacc_yyss, *yyss, old_info*sizeof(**yyss));
+ memcpy(state->yacc_yyvs, *yyvs, old_info*sizeof(**yyvs));
}
- *yyss=(short*) lex->yacc_yyss;
- *yyvs=(YYSTYPE*) lex->yacc_yyvs;
+ *yyss= (short*) state->yacc_yyss;
+ *yyvs= (YYSTYPE*) state->yacc_yyvs;
return 0;
}
@@ -5609,10 +5661,10 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
sp_cache_flush_obsolete(&thd->sp_proc_cache);
sp_cache_flush_obsolete(&thd->sp_func_cache);
- Lex_input_stream lip(thd, inBuf, length);
+ Parser_state parser_state(thd, inBuf, length);
- bool err= parse_sql(thd, &lip, NULL);
- *found_semicolon= lip.found_semicolon;
+ bool err= parse_sql(thd, & parser_state, NULL);
+ *found_semicolon= parser_state.m_lip.found_semicolon;
if (!err)
{
@@ -5641,6 +5693,11 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
(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);
}
@@ -5692,11 +5749,11 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
bool error= 0;
DBUG_ENTER("mysql_test_parse_for_slave");
- Lex_input_stream lip(thd, inBuf, length);
+ Parser_state parser_state(thd, inBuf, length);
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
- if (!parse_sql(thd, &lip, NULL) &&
+ if (!parse_sql(thd, & parser_state, NULL) &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */
thd->end_statement();
@@ -6735,7 +6792,7 @@ bool check_simple_select()
if (lex->current_select != &lex->select_lex)
{
char command[80];
- Lex_input_stream *lip= thd->m_lip;
+ Lex_input_stream *lip= & thd->m_parser_state->m_lip;
strmake(command, lip->yylval->symbol.str,
min(lip->yylval->symbol.length, sizeof(command)-1));
my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command);
@@ -7412,7 +7469,7 @@ extern int MYSQLparse(void *thd); // from sql_yacc.cc
instead of MYSQLparse().
@param thd Thread context.
- @param lip Lexer context.
+ @param parser_state Parser state.
@param creation_ctx Object creation context.
@return Error status.
@@ -7421,10 +7478,10 @@ extern int MYSQLparse(void *thd); // from sql_yacc.cc
*/
bool parse_sql(THD *thd,
- Lex_input_stream *lip,
+ Parser_state *parser_state,
Object_creation_ctx *creation_ctx)
{
- DBUG_ASSERT(thd->m_lip == NULL);
+ DBUG_ASSERT(thd->m_parser_state == NULL);
/* Backup creation context. */
@@ -7433,9 +7490,9 @@ bool parse_sql(THD *thd,
if (creation_ctx)
backup_ctx= creation_ctx->set_n_backup(thd);
- /* Set Lex_input_stream. */
+ /* Set parser state. */
- thd->m_lip= lip;
+ thd->m_parser_state= parser_state;
/* Parse the query. */
@@ -7446,9 +7503,9 @@ bool parse_sql(THD *thd,
DBUG_ASSERT(!mysql_parse_status ||
mysql_parse_status && thd->is_error());
- /* Reset Lex_input_stream. */
+ /* Reset parser state. */
- thd->m_lip= NULL;
+ thd->m_parser_state= NULL;
/* Restore creation context. */