mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 21:42:35 +01:00
Merge mkindahl@bk-internal.mysql.com:/home/bk/mysql-5.1-new-rpl
into capulet.net:/home/bk/mysql-5.1-rpl
This commit is contained in:
commit
1540b7f4ff
17 changed files with 404 additions and 298 deletions
|
@ -54,7 +54,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
|
|||
item_geofunc.cc item_subselect.cc item_row.cc\
|
||||
item_xmlfunc.cc \
|
||||
key.cc lock.cc log.cc sql_state.c \
|
||||
log_event.cc \
|
||||
log_event.cc rpl_record.cc \
|
||||
log_event_old.cc rpl_record_old.cc \
|
||||
protocol.cc net_serv.cc opt_range.cc \
|
||||
opt_sum.cc procedure.cc records.cc sql_acl.cc \
|
||||
|
|
|
@ -37,7 +37,7 @@ Replicate_Wild_Ignore_Table
|
|||
Last_Errno 0
|
||||
Last_Error
|
||||
Skip_Counter 0
|
||||
Exec_Master_Log_Pos 468
|
||||
Exec_Master_Log_Pos 754
|
||||
Relay_Log_Space #
|
||||
Until_Condition None
|
||||
Until_Log_File
|
||||
|
|
|
@ -99,33 +99,33 @@ show binlog events in 'slave-bin.000001' from 4;
|
|||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
slave-bin.000001 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4
|
||||
slave-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=NDB
|
||||
slave-bin.000001 # Query 1 # BEGIN
|
||||
slave-bin.000001 # Query 2 # BEGIN
|
||||
slave-bin.000001 # Table_map 2 # table_id: # (test.t1)
|
||||
slave-bin.000001 # Table_map 2 # table_id: # (mysql.ndb_apply_status)
|
||||
slave-bin.000001 # Write_rows 2 # table_id: #
|
||||
slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
|
||||
slave-bin.000001 # Query 1 # COMMIT
|
||||
slave-bin.000001 # Query 2 # COMMIT
|
||||
slave-bin.000001 # Query 1 # use `test`; drop table t1
|
||||
slave-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=NDB
|
||||
slave-bin.000001 # Query 1 # BEGIN
|
||||
slave-bin.000001 # Query 2 # BEGIN
|
||||
slave-bin.000001 # Table_map 2 # table_id: # (test.t1)
|
||||
slave-bin.000001 # Table_map 2 # table_id: # (mysql.ndb_apply_status)
|
||||
slave-bin.000001 # Write_rows 2 # table_id: #
|
||||
slave-bin.000001 # Write_rows 1 # table_id: #
|
||||
slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
|
||||
slave-bin.000001 # Query 1 # COMMIT
|
||||
slave-bin.000001 # Query 2 # COMMIT
|
||||
slave-bin.000001 # Query 1 # use `test`; create table t3 (a int)ENGINE=NDB
|
||||
slave-bin.000001 # Rotate 2 # slave-bin.000002;pos=4
|
||||
show binlog events in 'slave-bin.000002' from 4;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
slave-bin.000002 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4
|
||||
slave-bin.000002 # Query 1 # use `test`; create table t2 (n int)ENGINE=NDB
|
||||
slave-bin.000002 # Query 1 # BEGIN
|
||||
slave-bin.000002 # Query 2 # BEGIN
|
||||
slave-bin.000002 # Table_map 2 # table_id: # (test.t2)
|
||||
slave-bin.000002 # Table_map 2 # table_id: # (mysql.ndb_apply_status)
|
||||
slave-bin.000002 # Write_rows 2 # table_id: #
|
||||
slave-bin.000002 # Write_rows 1 # table_id: # flags: STMT_END_F
|
||||
slave-bin.000002 # Query 1 # COMMIT
|
||||
slave-bin.000002 # Query 2 # COMMIT
|
||||
show slave status;
|
||||
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert
|
||||
# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 617 # # master-bin.000002 Yes Yes # 0 0 617 # None 0 No # No
|
||||
|
|
|
@ -47,7 +47,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
|
|||
hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc
|
||||
item_create.cc item_func.cc item_geofunc.cc item_row.cc
|
||||
item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
|
||||
key.cc log.cc lock.cc log_event.cc message.rc
|
||||
key.cc log.cc lock.cc message.rc
|
||||
log_event.cc rpl_record.cc
|
||||
log_event_old.cc rpl_record_old.cc
|
||||
message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c
|
||||
mysqld.cc net_serv.cc
|
||||
|
|
|
@ -57,8 +57,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||
log.h sql_show.h rpl_rli.h rpl_mi.h \
|
||||
sql_select.h structs.h table.h sql_udf.h hash_filo.h \
|
||||
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
|
||||
log_event.h sql_repl.h slave.h rpl_filter.h \
|
||||
rpl_injector.h \
|
||||
sql_repl.h slave.h rpl_filter.h rpl_injector.h \
|
||||
log_event.h rpl_record.h \
|
||||
log_event_old.h rpl_record_old.h \
|
||||
stacktrace.h sql_sort.h sql_cache.h set_var.h \
|
||||
spatial.h gstream.h client_settings.h tzfile.h \
|
||||
|
@ -87,8 +87,9 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
|||
sql_prepare.cc sql_error.cc sql_locale.cc \
|
||||
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
|
||||
procedure.cc sql_test.cc \
|
||||
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
|
||||
log.cc init.cc derror.cc sql_acl.cc \
|
||||
unireg.cc des_key_file.cc \
|
||||
log_event.cc rpl_record.cc \
|
||||
log_event_old.cc rpl_record_old.cc \
|
||||
discover.cc time.cc opt_range.cc opt_sum.cc \
|
||||
records.cc filesort.cc handler.cc \
|
||||
|
|
158
sql/log_event.cc
158
sql/log_event.cc
|
@ -26,6 +26,7 @@
|
|||
#include "rpl_mi.h"
|
||||
#include "rpl_filter.h"
|
||||
#include "rpl_utility.h"
|
||||
#include "rpl_record.h"
|
||||
#include <my_dir.h>
|
||||
#endif /* MYSQL_CLIENT */
|
||||
#include <base64.h>
|
||||
|
@ -5811,163 +5812,6 @@ int Rows_log_event::do_add_row_data(byte *const row_data,
|
|||
#endif
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
/*
|
||||
Unpack a row into table->record[0].
|
||||
|
||||
SYNOPSIS
|
||||
unpack_row()
|
||||
rli Relay log info
|
||||
table Table to unpack into
|
||||
colcnt Number of columns to read from record
|
||||
row Packed row data
|
||||
cols Pointer to columns data to fill in
|
||||
row_end Pointer to variable that will hold the value of the
|
||||
one-after-end position for the row
|
||||
master_reclength
|
||||
Pointer to variable that will be set to the length of the
|
||||
record on the master side
|
||||
rw_set Pointer to bitmap that holds either the read_set or the
|
||||
write_set of the table
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The function will always unpack into the table->record[0]
|
||||
record. This is because there are too many dependencies on
|
||||
where the various member functions of Field and subclasses
|
||||
expect to write.
|
||||
|
||||
The row is assumed to only consist of the fields for which the
|
||||
bitset represented by 'arr' and 'bits'; the other parts of the
|
||||
record are left alone.
|
||||
|
||||
At most 'colcnt' columns are read: if the table is larger than
|
||||
that, the remaining fields are not filled in.
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
Error code, or zero if no error. The following error codes can
|
||||
be returned:
|
||||
|
||||
ER_NO_DEFAULT_FOR_FIELD
|
||||
Returned if one of the fields existing on the slave but not on
|
||||
the master does not have a default value (and isn't nullable)
|
||||
*/
|
||||
static int
|
||||
unpack_row(RELAY_LOG_INFO const *rli,
|
||||
TABLE *table, uint const colcnt,
|
||||
char const *const row_data, MY_BITMAP const *cols,
|
||||
char const **const row_end, ulong *const master_reclength,
|
||||
MY_BITMAP* const rw_set, Log_event_type const event_type)
|
||||
{
|
||||
DBUG_ENTER("unpack_row");
|
||||
DBUG_ASSERT(row_data);
|
||||
my_size_t const master_null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
|
||||
int error= 0;
|
||||
|
||||
char const *null_ptr= row_data;
|
||||
char const *pack_ptr= row_data + master_null_byte_count;
|
||||
|
||||
bitmap_clear_all(rw_set);
|
||||
|
||||
empty_record(table);
|
||||
|
||||
Field **const begin_ptr = table->field;
|
||||
Field **field_ptr;
|
||||
Field **const end_ptr= begin_ptr + colcnt;
|
||||
|
||||
DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
|
||||
|
||||
// Mask to mask out the correct bit among the null bits
|
||||
unsigned int null_mask= 1U;
|
||||
// The "current" null bits
|
||||
unsigned int null_bits= *null_ptr++;
|
||||
for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
|
||||
{
|
||||
Field *const f= *field_ptr;
|
||||
|
||||
/*
|
||||
No need to bother about columns that does not exist: they have
|
||||
gotten default values when being emptied above.
|
||||
*/
|
||||
if (bitmap_is_set(cols, field_ptr - begin_ptr))
|
||||
{
|
||||
if ((null_mask & 0xFF) == 0)
|
||||
{
|
||||
DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
|
||||
null_mask= 1U;
|
||||
null_bits= *null_ptr++;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
|
||||
|
||||
/* Field...::unpack() cannot return 0 */
|
||||
DBUG_ASSERT(pack_ptr != NULL);
|
||||
|
||||
if ((null_bits & null_mask) && f->maybe_null())
|
||||
f->set_null();
|
||||
else
|
||||
{
|
||||
f->set_notnull();
|
||||
|
||||
/*
|
||||
We only unpack the field if it was non-null
|
||||
*/
|
||||
pack_ptr= f->unpack(f->ptr, pack_ptr);
|
||||
}
|
||||
|
||||
bitmap_set_bit(rw_set, f->field_index);
|
||||
null_mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We should now have read all the null bytes, otherwise something is
|
||||
really wrong.
|
||||
*/
|
||||
DBUG_ASSERT(null_ptr == row_data + master_null_byte_count);
|
||||
|
||||
*row_end = pack_ptr;
|
||||
if (master_reclength)
|
||||
{
|
||||
if (*field_ptr)
|
||||
*master_reclength = (*field_ptr)->ptr - (char*) table->record[0];
|
||||
else
|
||||
*master_reclength = table->s->reclength;
|
||||
}
|
||||
|
||||
/*
|
||||
Set properties for remaining columns, if there are any. We let the
|
||||
corresponding bit in the write_set be set, to write the value if
|
||||
it was not there already. We iterate over all remaining columns,
|
||||
even if there were an error, to get as many error messages as
|
||||
possible. We are still able to return a pointer to the next row,
|
||||
so redo that.
|
||||
|
||||
This generation of error messages is only relevant when inserting
|
||||
new rows.
|
||||
*/
|
||||
for ( ; *field_ptr ; ++field_ptr)
|
||||
{
|
||||
uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
|
||||
Field *const f= *field_ptr;
|
||||
|
||||
if (event_type == WRITE_ROWS_EVENT &&
|
||||
((*field_ptr)->flags & mask) == mask)
|
||||
{
|
||||
slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD,
|
||||
"Field `%s` of table `%s`.`%s` "
|
||||
"has no default value and cannot be NULL",
|
||||
(*field_ptr)->field_name, table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
error = ER_NO_DEFAULT_FOR_FIELD;
|
||||
}
|
||||
else
|
||||
f->set_default();
|
||||
}
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli)
|
||||
{
|
||||
DBUG_ENTER("Rows_log_event::do_apply_event(st_relay_log_info*)");
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
int
|
||||
Write_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
||||
Write_rows_log_event_old::do_prepare_row(THD *thd,
|
||||
RELAY_LOG_INFO const *rli,
|
||||
TABLE *table,
|
||||
char const *row_start,
|
||||
char const **row_end)
|
||||
|
@ -14,7 +15,8 @@ Write_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
|||
DBUG_ASSERT(row_start && row_end);
|
||||
|
||||
int error;
|
||||
error= unpack_row_old(rli, table, m_width, table->record[0],
|
||||
error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
|
||||
table, m_width, table->record[0],
|
||||
row_start, &m_cols, row_end, &m_master_reclength,
|
||||
table->write_set, PRE_GA_WRITE_ROWS_EVENT);
|
||||
bitmap_copy(table->read_set, table->write_set);
|
||||
|
@ -23,7 +25,8 @@ Write_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
|||
|
||||
|
||||
int
|
||||
Delete_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
||||
Delete_rows_log_event_old::do_prepare_row(THD *thd,
|
||||
RELAY_LOG_INFO const *rli,
|
||||
TABLE *table,
|
||||
char const *row_start,
|
||||
char const **row_end)
|
||||
|
@ -36,7 +39,8 @@ Delete_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
|||
*/
|
||||
DBUG_ASSERT(table->s->fields >= m_width);
|
||||
|
||||
error= unpack_row_old(rli, table, m_width, table->record[0],
|
||||
error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
|
||||
table, m_width, table->record[0],
|
||||
row_start, &m_cols, row_end, &m_master_reclength,
|
||||
table->read_set, PRE_GA_DELETE_ROWS_EVENT);
|
||||
/*
|
||||
|
@ -54,7 +58,8 @@ Delete_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
|||
}
|
||||
|
||||
|
||||
int Update_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
||||
int Update_rows_log_event_old::do_prepare_row(THD *thd,
|
||||
RELAY_LOG_INFO const *rli,
|
||||
TABLE *table,
|
||||
char const *row_start,
|
||||
char const **row_end)
|
||||
|
@ -68,12 +73,14 @@ int Update_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
|
|||
DBUG_ASSERT(table->s->fields >= m_width);
|
||||
|
||||
/* record[0] is the before image for the update */
|
||||
error= unpack_row_old(rli, table, m_width, table->record[0],
|
||||
error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
|
||||
table, m_width, table->record[0],
|
||||
row_start, &m_cols, row_end, &m_master_reclength,
|
||||
table->read_set, PRE_GA_UPDATE_ROWS_EVENT);
|
||||
row_start = *row_end;
|
||||
/* m_after_image is the after image for the update */
|
||||
error= unpack_row_old(rli, table, m_width, m_after_image,
|
||||
error= unpack_row_old(const_cast<RELAY_LOG_INFO*>(rli),
|
||||
table, m_width, m_after_image,
|
||||
row_start, &m_cols, row_end, &m_master_reclength,
|
||||
table->write_set, PRE_GA_UPDATE_ROWS_EVENT);
|
||||
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
/* Copyright 2007 MySQL AB. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef LOG_EVENT_OLD_H
|
||||
#define LOG_EVENT_OLD_H
|
||||
|
||||
|
@ -15,6 +30,13 @@ public:
|
|||
TYPE_CODE = PRE_GA_WRITE_ROWS_EVENT
|
||||
};
|
||||
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
Write_rows_log_event_old(THD *thd, TABLE *table, ulong table_id,
|
||||
MY_BITMAP const *cols, bool is_transactional)
|
||||
: Write_rows_log_event(thd, table, table_id, cols, is_transactional)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_REPLICATION)
|
||||
Write_rows_log_event_old(const char *buf, uint event_len,
|
||||
const Format_description_log_event *descr)
|
||||
|
@ -27,7 +49,7 @@ private:
|
|||
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
|
||||
virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
|
||||
char const *row_start, char const **row_end);
|
||||
#endif
|
||||
};
|
||||
|
@ -42,6 +64,13 @@ public:
|
|||
TYPE_CODE = PRE_GA_UPDATE_ROWS_EVENT
|
||||
};
|
||||
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
Update_rows_log_event_old(THD *thd, TABLE *table, ulong table_id,
|
||||
MY_BITMAP const *cols, bool is_transactional)
|
||||
: Update_rows_log_event(thd, table, table_id, cols, is_transactional)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_REPLICATION)
|
||||
Update_rows_log_event_old(const char *buf, uint event_len,
|
||||
const Format_description_log_event *descr)
|
||||
|
@ -54,7 +83,7 @@ private:
|
|||
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
|
||||
virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
|
||||
char const *row_start, char const **row_end);
|
||||
#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
|
||||
};
|
||||
|
@ -69,6 +98,13 @@ public:
|
|||
TYPE_CODE = PRE_GA_DELETE_ROWS_EVENT
|
||||
};
|
||||
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
Delete_rows_log_event_old(THD *thd, TABLE *table, ulong table_id,
|
||||
MY_BITMAP const *cols, bool is_transactional)
|
||||
: Delete_rows_log_event(thd, table, table_id, cols, is_transactional)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_REPLICATION)
|
||||
Delete_rows_log_event_old(const char *buf, uint event_len,
|
||||
const Format_description_log_event *descr)
|
||||
|
@ -81,7 +117,7 @@ private:
|
|||
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
|
||||
virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*,
|
||||
char const *row_start, char const **row_end);
|
||||
#endif
|
||||
};
|
||||
|
|
278
sql/rpl_record.cc
Normal file
278
sql/rpl_record.cc
Normal file
|
@ -0,0 +1,278 @@
|
|||
/* Copyright 2007 MySQL AB. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "rpl_record.h"
|
||||
#include "slave.h" // Need to pull in slave_print_msg
|
||||
|
||||
/**
|
||||
Pack a record of data for a table into a format suitable for
|
||||
transfer via the binary log.
|
||||
|
||||
The format for a row in transfer with N fields is the following:
|
||||
|
||||
ceil(N/8) null bytes:
|
||||
One null bit for every column *regardless of whether it can be
|
||||
null or not*. This simplifies the decoding. Observe that the
|
||||
number of null bits is equal to the number of set bits in the
|
||||
@c cols bitmap. The number of null bytes is the smallest number
|
||||
of bytes necessary to store the null bits.
|
||||
|
||||
Padding bits are 1.
|
||||
|
||||
N packets:
|
||||
Each field is stored in packed format.
|
||||
|
||||
|
||||
@param table Table describing the format of the record
|
||||
|
||||
@param cols Bitmap with a set bit for each column that should
|
||||
be stored in the row
|
||||
|
||||
@param row_data Pointer to memory where row will be written
|
||||
|
||||
@param record Pointer to record that should be packed. It is
|
||||
assumed that the pointer refers to either @c
|
||||
record[0] or @c record[1], but no such check is
|
||||
made since the code does not rely on that.
|
||||
|
||||
@return The number of bytes written at @c row_data.
|
||||
*/
|
||||
my_size_t
|
||||
pack_row(TABLE *table, MY_BITMAP const* cols,
|
||||
byte *const row_data, const byte *record)
|
||||
{
|
||||
Field **p_field= table->field, *field;
|
||||
int const null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
|
||||
byte *pack_ptr = row_data + null_byte_count;
|
||||
byte *null_ptr = row_data;
|
||||
my_ptrdiff_t const rec_offset= record - table->record[0];
|
||||
my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
|
||||
|
||||
/*
|
||||
We write the null bits and the packed records using one pass
|
||||
through all the fields. The null bytes are written little-endian,
|
||||
i.e., the first fields are in the first byte.
|
||||
*/
|
||||
unsigned int null_bits= (1U << 8) - 1;
|
||||
// Mask to mask out the correct but among the null bits
|
||||
unsigned int null_mask= 1U;
|
||||
for ( ; (field= *p_field) ; p_field++)
|
||||
{
|
||||
DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
|
||||
null_mask, null_ptr, row_data, null_byte_count));
|
||||
if (bitmap_is_set(cols, p_field - table->field))
|
||||
{
|
||||
my_ptrdiff_t offset;
|
||||
if (field->is_null(rec_offset))
|
||||
{
|
||||
offset= def_offset;
|
||||
null_bits |= null_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset= rec_offset;
|
||||
null_bits &= ~null_mask;
|
||||
|
||||
/*
|
||||
We only store the data of the field if it is non-null
|
||||
*/
|
||||
pack_ptr= (byte*)field->pack((char *) pack_ptr, field->ptr + offset);
|
||||
}
|
||||
|
||||
null_mask <<= 1;
|
||||
if ((null_mask & 0xFF) == 0)
|
||||
{
|
||||
DBUG_ASSERT(null_ptr < row_data + null_byte_count);
|
||||
null_mask = 1U;
|
||||
*null_ptr++ = null_bits;
|
||||
null_bits= (1U << 8) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Write the last (partial) byte, if there is one
|
||||
*/
|
||||
if ((null_mask & 0xFF) > 1)
|
||||
{
|
||||
DBUG_ASSERT(null_ptr < row_data + null_byte_count);
|
||||
*null_ptr++ = null_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
The null pointer should now point to the first byte of the
|
||||
packed data. If it doesn't, something is very wrong.
|
||||
*/
|
||||
DBUG_ASSERT(null_ptr == row_data + null_byte_count);
|
||||
|
||||
return static_cast<my_size_t>(pack_ptr - row_data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Unpack a row into @c table->record[0].
|
||||
|
||||
The function will always unpack into the @c table->record[0]
|
||||
record. This is because there are too many dependencies on where
|
||||
the various member functions of Field and subclasses expect to
|
||||
write.
|
||||
|
||||
The row is assumed to only consist of the fields for which the
|
||||
bitset represented by @c arr and @c bits; the other parts of the
|
||||
record are left alone.
|
||||
|
||||
At most @c colcnt columns are read: if the table is larger than
|
||||
that, the remaining fields are not filled in.
|
||||
|
||||
@param rli Relay log info
|
||||
@param table Table to unpack into
|
||||
@param colcnt Number of columns to read from record
|
||||
@param row Packed row data
|
||||
@param cols Pointer to columns data to fill in
|
||||
@param row_end Pointer to variable that will hold the value of the
|
||||
one-after-end position for the row
|
||||
@param master_reclength
|
||||
Pointer to variable that will be set to the length of the
|
||||
record on the master side
|
||||
@param rw_set Pointer to bitmap that holds either the read_set or the
|
||||
write_set of the table
|
||||
|
||||
|
||||
@retval 0 No error
|
||||
|
||||
@retval ER_NO_DEFAULT_FOR_FIELD
|
||||
Returned if one of the fields existing on the slave but not on the
|
||||
master does not have a default value (and isn't nullable)
|
||||
|
||||
*/
|
||||
#ifdef HAVE_REPLICATION
|
||||
int
|
||||
unpack_row(RELAY_LOG_INFO const *rli,
|
||||
TABLE *table, uint const colcnt,
|
||||
char const *const row_data, MY_BITMAP const *cols,
|
||||
char const **const row_end, ulong *const master_reclength,
|
||||
MY_BITMAP* const rw_set, Log_event_type const event_type)
|
||||
{
|
||||
DBUG_ENTER("unpack_row");
|
||||
DBUG_ASSERT(row_data);
|
||||
my_size_t const master_null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
|
||||
int error= 0;
|
||||
|
||||
char const *null_ptr= row_data;
|
||||
char const *pack_ptr= row_data + master_null_byte_count;
|
||||
|
||||
bitmap_clear_all(rw_set);
|
||||
|
||||
empty_record(table);
|
||||
|
||||
Field **const begin_ptr = table->field;
|
||||
Field **field_ptr;
|
||||
Field **const end_ptr= begin_ptr + colcnt;
|
||||
|
||||
DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
|
||||
|
||||
// Mask to mask out the correct bit among the null bits
|
||||
unsigned int null_mask= 1U;
|
||||
// The "current" null bits
|
||||
unsigned int null_bits= *null_ptr++;
|
||||
for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr)
|
||||
{
|
||||
Field *const f= *field_ptr;
|
||||
|
||||
/*
|
||||
No need to bother about columns that does not exist: they have
|
||||
gotten default values when being emptied above.
|
||||
*/
|
||||
if (bitmap_is_set(cols, field_ptr - begin_ptr))
|
||||
{
|
||||
if ((null_mask & 0xFF) == 0)
|
||||
{
|
||||
DBUG_ASSERT(null_ptr < row_data + master_null_byte_count);
|
||||
null_mask= 1U;
|
||||
null_bits= *null_ptr++;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
|
||||
|
||||
/* Field...::unpack() cannot return 0 */
|
||||
DBUG_ASSERT(pack_ptr != NULL);
|
||||
|
||||
if ((null_bits & null_mask) && f->maybe_null())
|
||||
f->set_null();
|
||||
else
|
||||
{
|
||||
f->set_notnull();
|
||||
|
||||
/*
|
||||
We only unpack the field if it was non-null
|
||||
*/
|
||||
pack_ptr= f->unpack(f->ptr, pack_ptr);
|
||||
}
|
||||
|
||||
bitmap_set_bit(rw_set, f->field_index);
|
||||
null_mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We should now have read all the null bytes, otherwise something is
|
||||
really wrong.
|
||||
*/
|
||||
DBUG_ASSERT(null_ptr == row_data + master_null_byte_count);
|
||||
|
||||
*row_end = pack_ptr;
|
||||
if (master_reclength)
|
||||
{
|
||||
if (*field_ptr)
|
||||
*master_reclength = (*field_ptr)->ptr - (char*) table->record[0];
|
||||
else
|
||||
*master_reclength = table->s->reclength;
|
||||
}
|
||||
|
||||
/*
|
||||
Set properties for remaining columns, if there are any. We let the
|
||||
corresponding bit in the write_set be set, to write the value if
|
||||
it was not there already. We iterate over all remaining columns,
|
||||
even if there were an error, to get as many error messages as
|
||||
possible. We are still able to return a pointer to the next row,
|
||||
so redo that.
|
||||
|
||||
This generation of error messages is only relevant when inserting
|
||||
new rows.
|
||||
*/
|
||||
for ( ; *field_ptr ; ++field_ptr)
|
||||
{
|
||||
uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG;
|
||||
Field *const f= *field_ptr;
|
||||
|
||||
if (event_type == WRITE_ROWS_EVENT &&
|
||||
((*field_ptr)->flags & mask) == mask)
|
||||
{
|
||||
slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD,
|
||||
"Field `%s` of table `%s`.`%s` "
|
||||
"has no default value and cannot be NULL",
|
||||
(*field_ptr)->field_name, table->s->db.str,
|
||||
table->s->table_name.str);
|
||||
error = ER_NO_DEFAULT_FOR_FIELD;
|
||||
}
|
||||
else
|
||||
f->set_default();
|
||||
}
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
#endif // HAVE_REPLICATION
|
33
sql/rpl_record.h
Normal file
33
sql/rpl_record.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* Copyright 2007 MySQL AB. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef RPL_RECORD_H
|
||||
#define RPL_RECORD_H
|
||||
|
||||
#if !defined(MYSQL_CLIENT)
|
||||
my_size_t pack_row(TABLE* table, MY_BITMAP const* cols,
|
||||
byte *row_data, const byte *data);
|
||||
#endif
|
||||
|
||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||
int unpack_row(RELAY_LOG_INFO const *rli,
|
||||
TABLE *table, uint const colcnt,
|
||||
char const *const row_data, MY_BITMAP const *cols,
|
||||
char const **const row_end, ulong *const master_reclength,
|
||||
MY_BITMAP* const rw_set,
|
||||
Log_event_type const event_type);
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -3,7 +3,7 @@
|
|||
#include "rpl_record_old.h"
|
||||
|
||||
my_size_t
|
||||
pack_row_old(THD *thd, TABLE *table, MY_BITMAP const* cols,
|
||||
pack_row_old(TABLE *table, MY_BITMAP const* cols,
|
||||
byte *row_data, const byte *record)
|
||||
{
|
||||
Field **p_field= table->field, *field;
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
/* Copyright 2007 MySQL AB. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef RPL_RECORD_OLD_H
|
||||
#define RPL_RECORD_OLD_H
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
my_size_t pack_row_old(THD *thd, TABLE *table, MY_BITMAP const* cols,
|
||||
my_size_t pack_row_old(TABLE *table, MY_BITMAP const* cols,
|
||||
byte *row_data, const byte *record);
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
|
|
@ -1088,7 +1088,7 @@ bool st_relay_log_info::cached_charset_compare(char *charset) const
|
|||
|
||||
|
||||
void st_relay_log_info::stmt_done(my_off_t const event_master_log_pos,
|
||||
time_t event_creation_time)
|
||||
my_time_t event_creation_time)
|
||||
{
|
||||
clear_flag(IN_STMT);
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ typedef struct st_relay_log_info
|
|||
ulonglong future_group_master_log_pos;
|
||||
#endif
|
||||
|
||||
time_t last_master_timestamp;
|
||||
my_time_t last_master_timestamp;
|
||||
|
||||
void clear_slave_error();
|
||||
void clear_until_condition();
|
||||
|
@ -345,7 +345,7 @@ typedef struct st_relay_log_info
|
|||
the <code>Seconds_behind_master</code> field.
|
||||
*/
|
||||
void stmt_done(my_off_t event_log_pos,
|
||||
time_t event_creation_time);
|
||||
my_time_t event_creation_time);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1334,8 +1334,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi)
|
|||
if ((mi->slave_running == MYSQL_SLAVE_RUN_CONNECT) &&
|
||||
mi->rli.slave_running)
|
||||
{
|
||||
long time_diff= ((long)((time_t)time((time_t*) 0)
|
||||
- mi->rli.last_master_timestamp)
|
||||
long time_diff= ((long)(time(0) - mi->rli.last_master_timestamp)
|
||||
- mi->clock_diff_with_master);
|
||||
/*
|
||||
Apparently on some systems time_diff can be <0. Here are possible
|
||||
|
@ -3461,7 +3460,7 @@ static Log_event* next_event(RELAY_LOG_INFO* rli)
|
|||
the events have old timestamps (then you get "many", 0, "many").
|
||||
Transient phases like this can't really be fixed.
|
||||
*/
|
||||
time_t save_timestamp= rli->last_master_timestamp;
|
||||
my_time_t save_timestamp= rli->last_master_timestamp;
|
||||
rli->last_master_timestamp= 0;
|
||||
|
||||
DBUG_ASSERT(rli->relay_log.get_open_count() ==
|
||||
|
|
111
sql/sql_class.cc
111
sql/sql_class.cc
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "rpl_rli.h"
|
||||
#include "rpl_record.h"
|
||||
#include <my_bitmap.h>
|
||||
#include "log_event.h"
|
||||
#include <m_ctype.h>
|
||||
|
@ -2554,112 +2555,6 @@ my_size_t THD::max_row_length_blob(TABLE *table, const byte *data) const
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Pack a record of data for a table into a format suitable for
|
||||
transfer via the binary log.
|
||||
|
||||
SYNOPSIS
|
||||
THD::pack_row()
|
||||
table Table describing the format of the record
|
||||
cols Bitmap with a set bit for each column that should be
|
||||
stored in the row
|
||||
row_data Pointer to memory where row will be written
|
||||
record Pointer to record that should be packed. It is assumed
|
||||
that the pointer refers to either record[0] or
|
||||
record[1], but no such check is made since the code does
|
||||
not rely on that.
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
The format for a row in transfer with N fields is the following:
|
||||
|
||||
ceil(N/8) null bytes:
|
||||
One null bit for every column *regardless of whether it can be
|
||||
null or not*. This simplifies the decoding. Observe that the
|
||||
number of null bits is equal to the number of set bits in the
|
||||
'cols' bitmap. The number of null bytes is the smallest number
|
||||
of bytes necessary to store the null bits.
|
||||
|
||||
Padding bits are 1.
|
||||
|
||||
N packets:
|
||||
Each field is stored in packed format.
|
||||
|
||||
|
||||
RETURN VALUE
|
||||
|
||||
The number of bytes written at 'row_data'.
|
||||
*/
|
||||
my_size_t
|
||||
THD::pack_row(TABLE *table, MY_BITMAP const* cols,
|
||||
byte *const row_data, const byte *record) const
|
||||
{
|
||||
Field **p_field= table->field, *field;
|
||||
int const null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
|
||||
byte *pack_ptr = row_data + null_byte_count;
|
||||
byte *null_ptr = row_data;
|
||||
my_ptrdiff_t const rec_offset= record - table->record[0];
|
||||
my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
|
||||
|
||||
/*
|
||||
We write the null bits and the packed records using one pass
|
||||
through all the fields. The null bytes are written little-endian,
|
||||
i.e., the first fields are in the first byte.
|
||||
*/
|
||||
unsigned int null_bits= (1U << 8) - 1;
|
||||
// Mask to mask out the correct but among the null bits
|
||||
unsigned int null_mask= 1U;
|
||||
for ( ; (field= *p_field) ; p_field++)
|
||||
{
|
||||
DBUG_PRINT("debug", ("null_mask=%d; null_ptr=%p; row_data=%p; null_byte_count=%d",
|
||||
null_mask, null_ptr, row_data, null_byte_count));
|
||||
if (bitmap_is_set(cols, p_field - table->field))
|
||||
{
|
||||
my_ptrdiff_t offset;
|
||||
if (field->is_null(rec_offset))
|
||||
{
|
||||
offset= def_offset;
|
||||
null_bits |= null_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset= rec_offset;
|
||||
null_bits &= ~null_mask;
|
||||
|
||||
/*
|
||||
We only store the data of the field if it is non-null
|
||||
*/
|
||||
pack_ptr= (byte*)field->pack((char *) pack_ptr, field->ptr + offset);
|
||||
}
|
||||
|
||||
null_mask <<= 1;
|
||||
if ((null_mask & 0xFF) == 0)
|
||||
{
|
||||
DBUG_ASSERT(null_ptr < row_data + null_byte_count);
|
||||
null_mask = 1U;
|
||||
*null_ptr++ = null_bits;
|
||||
null_bits= (1U << 8) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Write the last (partial) byte, if there is one
|
||||
*/
|
||||
if ((null_mask & 0xFF) > 1)
|
||||
{
|
||||
DBUG_ASSERT(null_ptr < row_data + null_byte_count);
|
||||
*null_ptr++ = null_bits;
|
||||
}
|
||||
|
||||
/*
|
||||
The null pointer should now point to the first byte of the
|
||||
packed data. If it doesn't, something is very wrong.
|
||||
*/
|
||||
DBUG_ASSERT(null_ptr == row_data + null_byte_count);
|
||||
|
||||
return static_cast<my_size_t>(pack_ptr - row_data);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
@ -2830,9 +2725,9 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
|
|||
byte *before_row= row_data.slot(0);
|
||||
byte *after_row= row_data.slot(1);
|
||||
|
||||
my_size_t const before_size= pack_row(table, cols, before_row,
|
||||
my_size_t const before_size= pack_row(table, cols, before_row,
|
||||
before_record);
|
||||
my_size_t const after_size= pack_row(table, cols, after_row,
|
||||
my_size_t const after_size= pack_row(table, cols, after_row,
|
||||
after_record);
|
||||
|
||||
/*
|
||||
|
|
|
@ -1043,9 +1043,6 @@ public:
|
|||
return (length+max_row_length_blob(table,data));
|
||||
}
|
||||
|
||||
my_size_t pack_row(TABLE* table, MY_BITMAP const* cols, byte *row_data,
|
||||
const byte *data) const;
|
||||
|
||||
int binlog_flush_pending_rows_event(bool stmt_end);
|
||||
void binlog_delete_pending_rows_event();
|
||||
|
||||
|
|
Loading…
Reference in a new issue