diff options
author | Mats Kindahl <mats@mysql.com> | 2008-08-27 11:05:04 +0200 |
---|---|---|
committer | Mats Kindahl <mats@mysql.com> | 2008-08-27 11:05:04 +0200 |
commit | f295ea2f027f10a3646e6a5c64ed44317fd8c234 (patch) | |
tree | d632d6d00bde386bd8d2fd0b4f2f1a4493b5a4ff /sql | |
parent | 2d62bacf28fbeb60a66fddee978c480b3d89f3a8 (diff) | |
parent | 4e6de6ed27007c26a0ad249d6e0f1e6bf2af2d54 (diff) | |
download | mariadb-git-f295ea2f027f10a3646e6a5c64ed44317fd8c234.tar.gz |
Automerge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/log_event.cc | 52 | ||||
-rw-r--r-- | sql/log_event.h | 41 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_class.h | 8 | ||||
-rw-r--r-- | sql/sql_parse.cc | 48 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 |
6 files changed, 124 insertions, 30 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc index ff6afd013c5..b62edbf24c7 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1474,6 +1474,11 @@ void Query_log_event::pack_info(Protocol *protocol) static void write_str_with_code_and_len(char **dst, const char *src, int len, uint code) { + /* + only 1 byte to store the length of catalog, so it should not + surpass 255 + */ + DBUG_ASSERT(len <= 255); DBUG_ASSERT(src); *((*dst)++)= code; *((*dst)++)= (uchar) len; @@ -1493,21 +1498,8 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { - /** - @todo if catalog can be of length FN_REFLEN==512, then we are not - replicating it correctly, since the length is stored in a byte - /sven - */ - uchar buf[QUERY_HEADER_LEN+ - 1+4+ // code of flags2 and flags2 - 1+8+ // code of sql_mode and sql_mode - 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog - 1+4+ // code of autoinc and the 2 autoinc variables - 1+6+ // code of charset and charset - 1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name - 1+2+ // code of lc_time_names and lc_time_names_number - 1+2 // code of charset_database and charset_database_number - ], *start, *start_of_status; + uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS]; + uchar *start, *start_of_status; ulong event_length; if (!query) @@ -1613,10 +1605,8 @@ bool Query_log_event::write(IO_CACHE* file) { /* In the TZ sys table, column Name is of length 64 so this should be ok */ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH); - *start++= Q_TIME_ZONE_CODE; - *start++= time_zone_len; - memcpy(start, time_zone_str, time_zone_len); - start+= time_zone_len; + write_str_with_code_and_len((char **)(&start), + time_zone_str, time_zone_len, Q_TIME_ZONE_CODE); } if (lc_time_names_number) { @@ -1632,7 +1622,17 @@ bool Query_log_event::write(IO_CACHE* file) int2store(start, charset_database_number); start+= 2; } + if (table_map_for_update) + { + *start++= Q_TABLE_MAP_FOR_UPDATE_CODE; + int8store(start, table_map_for_update); + start+= 8; + } /* + NOTE: When adding new status vars, please don't forget to update + the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function + code_name in this file. + Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) { @@ -1709,7 +1709,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, auto_increment_increment(thd_arg->variables.auto_increment_increment), auto_increment_offset(thd_arg->variables.auto_increment_offset), lc_time_names_number(thd_arg->variables.lc_time_names->number), - charset_database_number(0) + charset_database_number(0), + table_map_for_update((ulonglong)thd_arg->table_map_for_update) { time_t end_time; @@ -1838,6 +1839,7 @@ code_name(int code) case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE"; case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; + case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE"; } sprintf(buf, "CODE#%d", code); return buf; @@ -1874,7 +1876,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db(NullS), catalog_len(0), status_vars_len(0), flags2_inited(0), sql_mode_inited(0), charset_inited(0), auto_increment_increment(1), auto_increment_offset(1), - time_zone_len(0), lc_time_names_number(0), charset_database_number(0) + time_zone_len(0), lc_time_names_number(0), charset_database_number(0), + table_map_for_update(0) { ulong data_len; uint32 tmp; @@ -2016,6 +2019,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, charset_database_number= uint2korr(pos); pos+= 2; break; + case Q_TABLE_MAP_FOR_UPDATE_CODE: + CHECK_SPACE(pos, end, 8); + table_map_for_update= uint8korr(pos); + pos+= 8; + break; default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -2423,6 +2431,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, else thd->variables.collation_database= thd->db_charset; + thd->table_map_for_update= (table_map)table_map_for_update; + /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); diff --git a/sql/log_event.h b/sql/log_event.h index 76d92b23189..041c41dc71b 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -237,12 +237,15 @@ struct sql_ex_info packet (i.e. a query) sent from client to master; First, an auxiliary log_event status vars estimation: */ -#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \ - 8 /* sql mode */ + \ - 1 + 1 + 255 /* catalog */ + \ - 4 /* autoinc */ + \ - 6 /* charset */ + \ - MAX_TIME_ZONE_NAME_LENGTH) +#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \ + 1 + 8 /* type, sql_mode */ + \ + 1 + 1 + 255 /* type, length, catalog */ + \ + 1 + 4 /* type, auto_increment */ + \ + 1 + 6 /* type, charset */ + \ + 1 + 1 + 255 /* type, length, time_zone */ + \ + 1 + 2 /* type, lc_time_names_number */ + \ + 1 + 2 /* type, charset_database_number */ + \ + 1 + 8 /* type, table_map_for_update */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -306,6 +309,8 @@ struct sql_ex_info #define Q_LC_TIME_NAMES_CODE 7 #define Q_CHARSET_DATABASE_CODE 8 + +#define Q_TABLE_MAP_FOR_UPDATE_CODE 9 /* Intvar event post-header */ #define I_TYPE_OFFSET 0 @@ -1455,6 +1460,22 @@ protected: This field is written if it is not 0. </td> </tr> + <tr> + <td>table_map_for_update</td> + <td>Q_TABLE_MAP_FOR_UPDATE_CODE == 9</td> + <td>8 byte integer</td> + + <td>The value of the table map that is to be updated by the + multi-table update query statement. Every bit of this variable + represents a table, and is set to 1 if the corresponding table is + to be updated by this statement. + + The value of this variable is set when executing a multi-table update + statement and used by slave to apply filter rules without opening + all the tables on slave. This is required because some tables may + not exist on slave because of the filter rules. + </td> + </tr> </table> @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions @@ -1471,6 +1492,9 @@ protected: * See Q_CHARSET_DATABASE_CODE in the table above. + * When adding new status vars, please don't forget to update the + MAX_SIZE_LOG_EVENT_STATUS, and update function code_name + */ class Query_log_event: public Log_event { @@ -1548,6 +1572,11 @@ public: const char *time_zone_str; uint lc_time_names_number; /* 0 means en_US */ uint charset_database_number; + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + ulonglong table_map_for_update; #ifndef MYSQL_CLIENT diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 186d6518676..4712caa5d1b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -514,6 +514,7 @@ THD::THD() lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), binlog_table_maps(0), binlog_flags(0UL), + table_map_for_update(0), arg_of_last_insert_id_function(FALSE), first_successful_insert_id_in_prev_stmt(0), first_successful_insert_id_in_prev_stmt_for_binlog(0), @@ -1113,6 +1114,8 @@ void THD::cleanup_after_query() free_items(); /* Reset where. */ where= THD::DEFAULT_WHERE; + /* reset table map for multi-table update */ + table_map_for_update= 0; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 9e0272b8891..8ceb93940ab 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -396,7 +396,6 @@ struct system_variables DATE_TIME_FORMAT *datetime_format; DATE_TIME_FORMAT *time_format; my_bool sysdate_is_now; - }; @@ -1446,6 +1445,13 @@ public: Note: in the parser, stmt_arena == thd, even for PS/SP. */ Query_arena *stmt_arena; + + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + table_map table_map_for_update; + /* Tells if LAST_INSERT_ID(#) was called for the current statement */ bool arg_of_last_insert_id_function; /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index dfa8233a37f..f88fff656cc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1902,6 +1902,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 @@ -1967,6 +1971,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 @@ -2881,7 +2927,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)) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 637bc00fe8a..b9ad88ee663 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1000,7 +1000,7 @@ reopen_tables: DBUG_RETURN(TRUE); } - tables_for_update= get_table_map(fields); + thd->table_map_for_update= tables_for_update= get_table_map(fields); /* Setup timestamp handling and locking mode |