summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <tsmith@ramayana.hindu.god>2008-02-05 16:04:07 -0700
committerunknown <tsmith@ramayana.hindu.god>2008-02-05 16:04:07 -0700
commitf328142cdb9f01dab47bb72df3df1ade57ee4ade (patch)
tree9ab45576cbc8bbff42e4bab3bd57abcd6af3fbb0 /sql
parentfb9c0158b2328d326acb9e9af9a2e85a72840afe (diff)
parent74bd1b0faf78929e0aaa7ba85bbf5a5800f75cba (diff)
downloadmariadb-git-f328142cdb9f01dab47bb72df3df1ade57ee4ade.tar.gz
Merge ramayana.hindu.god:/home/tsmith/m/bk/50
into ramayana.hindu.god:/home/tsmith/m/bk/build/50
Diffstat (limited to 'sql')
-rw-r--r--sql/log.cc100
-rw-r--r--sql/log_event.cc7
-rw-r--r--sql/set_var.cc1
-rw-r--r--sql/slave.cc5
-rw-r--r--sql/sql_acl.cc24
-rw-r--r--sql/sql_parse.cc1
-rw-r--r--sql/sql_repl.cc75
-rw-r--r--sql/sql_string.cc4
-rw-r--r--sql/sql_view.cc32
9 files changed, 164 insertions, 85 deletions
diff --git a/sql/log.cc b/sql/log.cc
index e66d965c613..0376facb473 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -122,6 +122,20 @@ static int binlog_prepare(THD *thd, bool all)
return 0;
}
+/**
+ This function is called once after each statement.
+
+ It has the responsibility to flush the transaction cache to the
+ binlog file on commits.
+
+ @param thd The client thread that executes the transaction.
+ @param all true if this is the last statement before a COMMIT
+ statement; false if either this is a statement in a
+ transaction but not the last, or if this is a statement
+ not inside a BEGIN block and autocommit is on.
+
+ @see handlerton::commit
+*/
static int binlog_commit(THD *thd, bool all)
{
IO_CACHE *trans_log= (IO_CACHE*)thd->ha_data[binlog_hton.slot];
@@ -134,7 +148,15 @@ static int binlog_commit(THD *thd, bool all)
// we're here because trans_log was flushed in MYSQL_LOG::log_xid()
DBUG_RETURN(0);
}
- if (all)
+ /*
+ Write commit event if at least one of the following holds:
+ - the user sends an explicit COMMIT; or
+ - the autocommit flag is on, and we are not inside a BEGIN.
+ However, if the user has not sent an explicit COMMIT, and we are
+ either inside a BEGIN or run with autocommit off, then this is not
+ the end of a transaction and we should not write a commit event.
+ */
+ if (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
@@ -144,6 +166,22 @@ static int binlog_commit(THD *thd, bool all)
DBUG_RETURN(binlog_end_trans(thd, trans_log, &invisible_commit));
}
+/**
+ This function is called when a transaction involving a transactional
+ table is rolled back.
+
+ It has the responsibility to flush the transaction cache to the
+ binlog file. However, if the transaction does not involve
+ non-transactional tables, nothing needs to be logged.
+
+ @param thd The client thread that executes the transaction.
+ @param all true if this is the last statement before a COMMIT
+ statement; false if either this is a statement in a
+ transaction but not the last, or if this is a statement
+ not inside a BEGIN block and autocommit is on.
+
+ @see handlerton::rollback
+*/
static int binlog_rollback(THD *thd, bool all)
{
int error=0;
@@ -1817,9 +1855,11 @@ uint MYSQL_LOG::next_file_id()
IMPLEMENTATION
- To support transaction over replication, we wrap the transaction
with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
- We want to write a BEGIN/ROLLBACK block when a non-transactional table
- was updated in a transaction which was rolled back. This is to ensure
- that the same updates are run on the slave.
+ If a transaction that only involves transactional tables is
+ rolled back, we do not binlog it. However, we write a
+ BEGIN/ROLLBACK block when a non-transactional table was updated
+ in a transaction which was rolled back. This is to ensure that
+ the same updates are run on the slave.
*/
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
@@ -1837,32 +1877,34 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
byte header[LOG_EVENT_HEADER_LEN];
/*
- Log "BEGIN" at the beginning of the transaction.
- which may contain more than 1 SQL statement.
+ Log "BEGIN" at the beginning of every transaction. Here, a
+ transaction is either a BEGIN..COMMIT block or a single
+ statement in autocommit mode.
*/
- if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
- {
- Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE);
- /*
- Imagine this is rollback due to net timeout, after all statements of
- the transaction succeeded. Then we want a zero-error code in BEGIN.
- In other words, if there was a really serious error code it's already
- in the statement's events, there is no need to put it also in this
- internally generated event, and as this event is generated late it
- would lead to false alarms.
- This is safer than thd->clear_error() against kills at shutdown.
- */
- qinfo.error_code= 0;
- /*
- Now this Query_log_event has artificial log_pos 0. It must be adjusted
- to reflect the real position in the log. Not doing it would confuse the
- slave: it would prevent this one from knowing where he is in the
- master's binlog, which would result in wrong positions being shown to
- the user, MASTER_POS_WAIT undue waiting etc.
- */
- if (qinfo.write(&log_file))
- goto err;
- }
+ Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE);
+ /*
+ Imagine this is rollback due to net timeout, after all
+ statements of the transaction succeeded. Then we want a
+ zero-error code in BEGIN. In other words, if there was a
+ really serious error code it's already in the statement's
+ events, there is no need to put it also in this internally
+ generated event, and as this event is generated late it would
+ lead to false alarms.
+
+ This is safer than thd->clear_error() against kills at shutdown.
+ */
+ qinfo.error_code= 0;
+ /*
+ Now this Query_log_event has artificial log_pos 0. It must be
+ adjusted to reflect the real position in the log. Not doing it
+ would confuse the slave: it would prevent this one from
+ knowing where he is in the master's binlog, which would result
+ in wrong positions being shown to the user, MASTER_POS_WAIT
+ undue waiting etc.
+ */
+ if (qinfo.write(&log_file))
+ goto err;
+
/* Read from the file used to cache the queries .*/
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
goto err;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d22973d12a3..a950094a018 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1862,7 +1862,7 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
{
print_query_header(file, print_event_info);
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
- fprintf(file, "%s\n", print_event_info->delimiter);
+ fprintf(file, "\n%s\n", print_event_info->delimiter);
}
#endif /* MYSQL_CLIENT */
@@ -3793,6 +3793,7 @@ Xid_log_event(const char* buf,
#ifndef MYSQL_CLIENT
bool Xid_log_event::write(IO_CACHE* file)
{
+ DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
return write_header(file, sizeof(xid)) ||
my_b_safe_write(file, (byte*) &xid, sizeof(xid));
}
@@ -5180,12 +5181,12 @@ void Execute_load_query_log_event::print(FILE* file,
fprintf(file, " INTO");
my_fwrite(file, (byte*) query + fn_pos_end, q_len-fn_pos_end,
MYF(MY_NABP | MY_WME));
- fprintf(file, "%s\n", print_event_info->delimiter);
+ fprintf(file, "\n%s\n", print_event_info->delimiter);
}
else
{
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
- fprintf(file, "%s\n", print_event_info->delimiter);
+ fprintf(file, "\n%s\n", print_event_info->delimiter);
}
if (!print_event_info->short_form)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index fe57b46745a..a99b063a97e 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1448,6 +1448,7 @@ static void fix_trans_mem_root(THD *thd, enum_var_type type)
static void fix_server_id(THD *thd, enum_var_type type)
{
server_id_supplied = 1;
+ thd->server_id= server_id;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 1509916fe91..4a65e9aaa85 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -3348,7 +3348,10 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
if (rli->slave_skip_counter &&
!((type_code == INTVAR_EVENT ||
type_code == RAND_EVENT ||
- type_code == USER_VAR_EVENT) &&
+ type_code == USER_VAR_EVENT ||
+ type_code == BEGIN_LOAD_QUERY_EVENT ||
+ type_code == APPEND_BLOCK_EVENT ||
+ type_code == CREATE_FILE_EVENT) &&
rli->slave_skip_counter == 1) &&
#if MYSQL_VERSION_ID < 50100
/*
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 134541368e9..8fdd054eb39 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -5333,6 +5333,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
LEX_USER *user_name, *tmp_user_name;
List_iterator <LEX_USER> user_list(list);
TABLE_LIST tables[GRANT_TABLES];
+ bool some_users_created= FALSE;
DBUG_ENTER("mysql_create_user");
/* CREATE USER may be skipped on replication client. */
@@ -5361,6 +5362,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
continue;
}
+ some_users_created= TRUE;
sql_mode= thd->variables.sql_mode;
if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
{
@@ -5371,7 +5373,10 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
- if (mysql_bin_log.is_open())
+ if (result)
+ my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
+
+ if (some_users_created && mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
@@ -5379,8 +5384,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
- if (result)
- my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
DBUG_RETURN(result);
}
@@ -5405,6 +5408,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
LEX_USER *user_name, *tmp_user_name;
List_iterator <LEX_USER> user_list(list);
TABLE_LIST tables[GRANT_TABLES];
+ bool some_users_deleted= FALSE;
DBUG_ENTER("mysql_drop_user");
/* DROP USER may be skipped on replication client. */
@@ -5426,7 +5430,9 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
{
append_user(&wrong_users, user_name);
result= TRUE;
+ continue;
}
+ some_users_deleted= TRUE;
}
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
@@ -5440,7 +5446,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno));
DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error));
- if (mysql_bin_log.is_open())
+ if (some_users_deleted && mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
@@ -5473,6 +5479,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
LEX_USER *user_to, *tmp_user_to;
List_iterator <LEX_USER> user_list(list);
TABLE_LIST tables[GRANT_TABLES];
+ bool some_users_renamed= FALSE;
DBUG_ENTER("mysql_rename_user");
/* RENAME USER may be skipped on replication client. */
@@ -5506,7 +5513,9 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
{
append_user(&wrong_users, user_from);
result= TRUE;
+ continue;
}
+ some_users_renamed= TRUE;
}
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
@@ -5514,7 +5523,10 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
- if (mysql_bin_log.is_open())
+ if (result)
+ my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
+
+ if (some_users_renamed && mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
@@ -5522,8 +5534,6 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
- if (result)
- my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
DBUG_RETURN(result);
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 8af79d77fa1..45dac4d5127 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2067,7 +2067,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
unregister_slave(thd,1,1);
/* fake COM_QUIT -- if we get here, the thread needs to terminate */
error = TRUE;
- net->error = 0;
break;
}
#endif
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 903d254db8f..5bbff69f197 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1229,9 +1229,6 @@ bool change_master(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(TRUE);
}
}
- mi->rli.group_master_log_pos = mi->master_log_pos;
- DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
-
/*
Coordinates in rli were spoilt by the 'if (need_relay_log_purge)' block,
so restore them to good values. If we left them to ''/0, that would work;
@@ -1243,6 +1240,7 @@ bool change_master(THD* thd, MASTER_INFO* mi)
That's why we always save good coords in rli.
*/
mi->rli.group_master_log_pos= mi->master_log_pos;
+ DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
strmake(mi->rli.group_master_log_name,mi->master_log_name,
sizeof(mi->rli.group_master_log_name)-1);
@@ -1355,6 +1353,11 @@ bool mysql_show_binlog_events(THD* thd)
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
goto err;
+ /*
+ to account binlog event header size
+ */
+ thd->variables.max_allowed_packet += MAX_LOG_EVENT_HEADER;
+
pthread_mutex_lock(log_lock);
/*
@@ -1365,7 +1368,6 @@ bool mysql_show_binlog_events(THD* thd)
This code will fail on a mixed relay log (one which has Format_desc then
Rotate then Format_desc).
*/
-
ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event);
if (ev)
{
@@ -1556,37 +1558,52 @@ err:
DBUG_RETURN(TRUE);
}
-
+/**
+ Load data's io cache specific hook to be executed
+ before a chunk of data is being read into the cache's buffer
+ The fuction instantianates and writes into the binlog
+ replication events along LOAD DATA processing.
+
+ @param file pointer to io-cache
+ @return 0
+*/
int log_loaded_block(IO_CACHE* file)
{
+ DBUG_ENTER("log_loaded_block");
LOAD_FILE_INFO *lf_info;
- uint block_len ;
-
- /* file->request_pos contains position where we started last read */
- char* buffer = (char*) file->request_pos;
- if (!(block_len = (char*) file->read_end - (char*) buffer))
- return 0;
- lf_info = (LOAD_FILE_INFO*) file->arg;
+ uint block_len;
+ /* buffer contains position where we started last read */
+ char* buffer= (char*) my_b_get_buffer_start(file);
+ uint max_event_size= current_thd->variables.max_allowed_packet;
+ lf_info= (LOAD_FILE_INFO*) file->arg;
if (lf_info->last_pos_in_file != HA_POS_ERROR &&
- lf_info->last_pos_in_file >= file->pos_in_file)
- return 0;
- lf_info->last_pos_in_file = file->pos_in_file;
- if (lf_info->wrote_create_file)
- {
- Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
- block_len, lf_info->log_delayed);
- mysql_bin_log.write(&a);
- }
- else
+ lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
+ DBUG_RETURN(0);
+
+ for (block_len= my_b_get_bytes_in_buffer(file); block_len > 0;
+ buffer += min(block_len, max_event_size),
+ block_len -= min(block_len, max_event_size))
{
- Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db,
- buffer, block_len,
- lf_info->log_delayed);
- mysql_bin_log.write(&b);
- lf_info->wrote_create_file = 1;
- DBUG_SYNC_POINT("debug_lock.created_file_event",10);
+ lf_info->last_pos_in_file= my_b_get_pos_in_file(file);
+ if (lf_info->wrote_create_file)
+ {
+ Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
+ min(block_len, max_event_size),
+ lf_info->log_delayed);
+ mysql_bin_log.write(&a);
+ }
+ else
+ {
+ Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db,
+ buffer,
+ min(block_len, max_event_size),
+ lf_info->log_delayed);
+ mysql_bin_log.write(&b);
+ lf_info->wrote_create_file= 1;
+ DBUG_SYNC_POINT("debug_lock.created_file_event",10);
+ }
}
- return 0;
+ DBUG_RETURN(0);
}
#endif /* HAVE_REPLICATION */
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 606a9ddb26d..75e47dd0c8e 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -307,8 +307,8 @@ bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset,
return TRUE;
/*
- Note, this is only safe for little-endian UCS-2.
- If we add big-endian UCS-2 sometimes, this code
+ Note, this is only safe for big-endian UCS-2.
+ If we add little-endian UCS-2 sometimes, this code
will be more complicated. But it's OK for now.
*/
bzero((char*) Ptr, offset);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 297edd0d90d..dd0b92a06f8 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1424,6 +1424,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
String non_existant_views;
char *wrong_object_db= NULL, *wrong_object_name= NULL;
bool error= FALSE;
+ bool some_views_deleted= FALSE;
+ bool something_wrong= FALSE;
VOID(pthread_mutex_lock(&LOCK_open));
for (view= views; view; view= view->next_local)
@@ -1462,33 +1464,37 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
}
if (my_delete(path, MYF(MY_WME)))
error= TRUE;
+ some_views_deleted= TRUE;
query_cache_invalidate3(thd, view, 0);
sp_cache_invalidate();
}
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
-
- VOID(pthread_mutex_unlock(&LOCK_open));
- if (error)
- {
- DBUG_RETURN(TRUE);
- }
if (wrong_object_name)
{
my_error(ER_WRONG_OBJECT, MYF(0), wrong_object_db, wrong_object_name,
"VIEW");
- DBUG_RETURN(TRUE);
}
if (non_existant_views.length())
{
my_error(ER_BAD_TABLE_ERROR, MYF(0), non_existant_views.c_ptr());
+ }
+
+ something_wrong= error || wrong_object_name || non_existant_views.length();
+ if (some_views_deleted || !something_wrong)
+ {
+ if (!something_wrong)
+ thd->clear_error();
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
+ mysql_bin_log.write(&qinfo);
+ }
+
+ VOID(pthread_mutex_unlock(&LOCK_open));
+
+ if (something_wrong)
+ {
DBUG_RETURN(TRUE);
}
+
send_ok(thd);
DBUG_RETURN(FALSE);
}