summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
authorunknown <mats@mysql.com>2006-02-16 08:46:45 +0100
committerunknown <mats@mysql.com>2006-02-16 08:46:45 +0100
commit738a1ca08db810aa37069da149aa21590292caac (patch)
tree3f960f1eee8ec7454fbf52e22f645085d4b004dd /sql/sql_class.cc
parent13adc06f53122cf890b8d58d21bc77a51132c80f (diff)
parent41f7d138539c01afbcb6efb2f772fae0e9c3cd05 (diff)
downloadmariadb-git-738a1ca08db810aa37069da149aa21590292caac.tar.gz
Merge mysql.com:/home/bkroot/mysql-5.1-new
into mysql.com:/home/bk/w3023-mysql-5.1-new mysql-test/extra/binlog_tests/ctype_cp932.test: Auto merged mysql-test/r/binlog_row_blackhole.result: Auto merged mysql-test/r/binlog_stm_ctype_cp932.result: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/lock.cc: Auto merged sql/log.cc: Auto merged sql/log.h: Auto merged sql/log_event.h: Auto merged sql/mysql_priv.h: Auto merged sql/opt_range.cc: Auto merged sql/parse_file.cc: Auto merged sql/slave.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_insert.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/table.h: Auto merged sql/log_event.cc: Merge with mysql-5.1-new
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc112
1 files changed, 74 insertions, 38 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index e68bcb9e281..f89e7ecbfe5 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -162,7 +162,7 @@ bool foreign_key_prefix(Key *a, Key *b)
****************************************************************************/
Open_tables_state::Open_tables_state(ulong version_arg)
- :version(version_arg)
+ :version(version_arg), state_flags(0U)
{
reset_open_tables_state();
}
@@ -197,7 +197,8 @@ THD::THD()
:Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
Open_tables_state(refresh_version), rli_fake(0),
lock_id(&main_lock_id),
- user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0),
+ user_time(0), in_sub_stmt(0), binlog_table_maps(0),
+ global_read_lock(0), is_fatal_error(0),
rand_used(0), time_zone_used(0),
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE),
@@ -1945,6 +1946,7 @@ void THD::reset_n_backup_open_tables_state(Open_tables_state *backup)
DBUG_ENTER("reset_n_backup_open_tables_state");
backup->set_open_tables_state(this);
reset_open_tables_state();
+ state_flags|= Open_tables_state::BACKUPS_AVAIL;
DBUG_VOID_RETURN;
}
@@ -2011,25 +2013,6 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup,
backup->client_capabilities= client_capabilities;
backup->savepoints= transaction.savepoints;
-#ifdef HAVE_ROW_BASED_REPLICATION
- /*
- For row-based replication and before executing a function/trigger,
- the pending rows event has to be flushed. The function/trigger
- might execute statement that require the pending event to be
- flushed. A simple example:
-
- CREATE FUNCTION foo() RETURNS INT
- BEGIN
- SAVEPOINT x;
- RETURN 0;
- END
-
- INSERT INTO t1 VALUES (1), (foo()), (2);
- */
- if (binlog_row_based)
- binlog_flush_pending_rows_event(false);
-#endif /* HAVE_ROW_BASED_REPLICATION */
-
if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) &&
!binlog_row_based)
options&= ~OPTION_BIN_LOG;
@@ -2209,6 +2192,7 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
bool is_transactional,
RowsEventT *hint __attribute__((unused)))
{
+ DBUG_ENTER("binlog_prepare_pending_rows_event");
/* Pre-conditions */
DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
@@ -2220,12 +2204,12 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
have to do it here.
*/
if (binlog_setup_trx_data())
- return NULL;
+ DBUG_RETURN(NULL);
Rows_log_event* pending= binlog_get_pending_rows_event();
if (unlikely(pending && !pending->is_valid()))
- return NULL;
+ DBUG_RETURN(NULL);
/*
Check if the current event is non-NULL and a write-rows
@@ -2250,7 +2234,7 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
ev= new RowsEventT(this, table, table->s->table_map_id, cols,
is_transactional);
if (unlikely(!ev))
- return NULL;
+ DBUG_RETURN(NULL);
ev->server_id= serv_id; // I don't like this, it's too easy to forget.
/*
flush the pending event and replace it with the newly created
@@ -2259,17 +2243,17 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(this, ev)))
{
delete ev;
- return NULL;
+ DBUG_RETURN(NULL);
}
- return ev; /* This is the new pending event */
+ DBUG_RETURN(ev); /* This is the new pending event */
}
- return pending; /* This is the current pending event */
+ DBUG_RETURN(pending); /* This is the current pending event */
}
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
/*
- Instansiate the versions we need, we have -fno-implicit-template as
+ Instantiate the versions we need, we have -fno-implicit-template as
compiling option.
*/
template Rows_log_event*
@@ -2534,14 +2518,33 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end)
{
pending->set_flags(Rows_log_event::STMT_END_F);
pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
+ binlog_table_maps= 0;
}
+ error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
+ }
+ else if (stmt_end && binlog_table_maps > 0)
+ { /* there is no pending event at this point */
/*
- We only bother to set the pending event if it is non-NULL. This
- is essential for correctness, since there is not necessarily a
- trx_data created for the thread if the pending event is NULL.
+ If pending is null and we are going to end the statement, we
+ have to write an extra, empty, binrow event so that the slave
+ knows to discard the tables it has received. Otherwise, the
+ table maps written this far will be included in the table maps
+ for the following statement.
+
+ See if we can replace this with a dummy, maybe constant, event.
*/
+#if 0
+ static unsigned char memory[sizeof(Write_rows_log_event)];
+ void *const ptr= &memory;
+#endif
+ Rows_log_event *ev=
+ new Write_rows_log_event(this, 0, ULONG_MAX, 0, FALSE);
+ ev->set_flags(Rows_log_event::STMT_END_F);
+ binlog_set_pending_rows_event(ev);
+
error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0);
+ binlog_table_maps= 0;
}
DBUG_RETURN(error);
@@ -2568,6 +2571,17 @@ void THD::binlog_delete_pending_rows_event()
functions have been issued, but before tables are unlocked and
closed.
+ OBSERVE
+ There shall be no writes to any system table after calling
+ binlog_query(), so these writes has to be moved to before the call
+ of binlog_query() for correct functioning.
+
+ This is necessesary not only for RBR, but the master might crash
+ after binlogging the query but before changing the system tables.
+ This means that the slave and the master are not in the same state
+ (after the master has restarted), so therefore we have to
+ eliminate this problem.
+
RETURN VALUE
Error code, or 0 if no error.
*/
@@ -2577,7 +2591,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
{
DBUG_ENTER("THD::binlog_query");
DBUG_ASSERT(query && mysql_bin_log.is_open());
- int error= binlog_flush_pending_rows_event(true);
+
switch (qtype)
{
case THD::MYSQL_QUERY_TYPE:
@@ -2591,19 +2605,41 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype,
*/
case THD::ROW_QUERY_TYPE:
if (binlog_row_based)
- DBUG_RETURN(binlog_flush_pending_rows_event(true));
+ {
+ /*
+ If thd->lock is set, then we are not inside a stored function.
+ In that case, mysql_unlock_tables() will be called after this
+ binlog_query(), so we have to flush the pending rows event
+ with the STMT_END_F set to unlock all tables at the slave side
+ as well.
+
+ We will not flush the pending event, if thd->lock is NULL.
+ This means that we are inside a stored function or trigger, so
+ the flushing will be done inside the top-most
+ close_thread_tables().
+ */
+ if (this->lock)
+ DBUG_RETURN(binlog_flush_pending_rows_event(TRUE));
+ DBUG_RETURN(0);
+ }
/* Otherwise, we fall through */
case THD::STMT_QUERY_TYPE:
/*
- Most callers of binlog_query() ignore the error code, assuming
- that the statement will always be written to the binlog. In
- case of error above, we therefore just continue and write the
- statement to the binary log.
+ The MYSQL_LOG::write() function will set the STMT_END_F flag and
+ flush the pending rows event if necessary.
*/
{
Query_log_event qinfo(this, query, query_len, is_trans, suppress_use);
qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
- DBUG_RETURN(mysql_bin_log.write(&qinfo));
+ /*
+ Binlog table maps will be irrelevant after a Query_log_event
+ (they are just removed on the slave side) so after the query
+ log event is written to the binary log, we pretend that no
+ table maps were written.
+ */
+ int error= mysql_bin_log.write(&qinfo);
+ binlog_table_maps= 0;
+ DBUG_RETURN(error);
}
break;