diff options
Diffstat (limited to 'sql/sql_parse.cc')
-rw-r--r-- | sql/sql_parse.cc | 115 |
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. */ |