summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMats Kindahl <mats@mysql.com>2008-08-27 11:05:04 +0200
committerMats Kindahl <mats@mysql.com>2008-08-27 11:05:04 +0200
commitf295ea2f027f10a3646e6a5c64ed44317fd8c234 (patch)
treed632d6d00bde386bd8d2fd0b4f2f1a4493b5a4ff /sql
parent2d62bacf28fbeb60a66fddee978c480b3d89f3a8 (diff)
parent4e6de6ed27007c26a0ad249d6e0f1e6bf2af2d54 (diff)
downloadmariadb-git-f295ea2f027f10a3646e6a5c64ed44317fd8c234.tar.gz
Automerge
Diffstat (limited to 'sql')
-rw-r--r--sql/log_event.cc52
-rw-r--r--sql/log_event.h41
-rw-r--r--sql/sql_class.cc3
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_parse.cc48
-rw-r--r--sql/sql_update.cc2
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